| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
EncodingPatternPreservation.captureAndReplaceMatches() previously used a fixed, publicly-known default marker (this class's simple name, "EncodingPatternPreservation") to temporarily stand in for matched content while the rest of the string is encoded. restoreOriginalContent() restores captured content in FIFO order using replaceFirst(marker, ...), matching the marker as plain literal text. If the input already contains that literal string ahead of the real matched content (e.g. CSSCodec.encode() on "EncodingPatternPreservation background:rgb(1,2,3)"), replaceFirst matches the attacker-supplied text instead of the real placeholder, silently desynchronizing every subsequent restoration and corrupting the encoded output. Fix: derive the default marker per-instance from a random UUID (with hyphens stripped, since a hyphen would itself be altered by an encoding pass such as CSSCodec's before restoration), so it cannot be predicted or embedded by input content. The public setReplacementMarker() API is unchanged. Added regression tests covering marker unpredictability and the literal-marker-in-input desync scenario.
|
Filed the underlying bug as #915 with repro details, per the issue → PR workflow described in CONTRIBUTING-TO-ESAPI.txt. |
Sorry, something went wrong.
|
Friendly ping — open since 14 July, with the underlying bug filed separately as #915 per CONTRIBUTING-TO-ESAPI.txt. It replaces the fixed, publicly-known default marker in EncodingPatternPreservation (the class's own simple name) so that attacker-supplied content matching the marker can't collide with it during the captureAndReplaceMatches() / restoreOriginalContent() round trip in CSSCodec. No rush — just noting it's ready when there's time. Happy to adjust the approach if you'd prefer a different fix for #915. |
Sorry, something went wrong.
|
Following up on this and #915 — coming up on a month since filing, wanted to check it's not stuck somewhere. |
Sorry, something went wrong.
|
Looking at the code submitted, I think that the solution provided solves the issue identified. The only issue I see and I'm not sure about is if this utility is ever used to write data to a location outside of the ESAPI JVM (EG: written to a flat-file between sessions) then the new instance will not be able to restore data from the previous instance since the markers are now guaranteed not to match. I do think that what is provided does correct the problem as identified; however, I would like to get @xeno6696 to weigh in on the case above before merging. If there are any clients who do write data between sessions, then this addition would break backwards compatibility and potentially cause loss of data. |
Sorry, something went wrong.
|
I agree with @jeremiahjstacey that the fix here matches the identified problem, but I'm mulling over the corner case he brought up. I think it's worth calling out in the release notes, but the method setReplacementMarker(String); is exposed and if we want old behavior to be restored, the client can use that method to reinsert the broken functionality that is now fixed. So yeah, worth calling out, but I wouldn't think to push this any deeper. Created a "release-notes" label to flag any content that we want to ensure gets rolled into notes for the next release. |
Sorry, something went wrong.
There was a problem hiding this comment.
Per agreement with @jeremiahjstacey, if you could just add the identified corner-case to the JavaDoc comment for the Codec I think release-notes should pick it up without additional fanfare.
Sorry, something went wrong.
There was a problem hiding this comment.
Thanks for the extra testing to boot, this was a high-quality first PR.
Sorry, something went wrong.
|
added the corner case to the class javadoc |
Sorry, something went wrong.
| Back | FazBrowse Home | New Git URL |
Summary
EncodingPatternPreservation (used by CSSCodec to protect rgb(...) triplets from CSS-escaping during encodeForCSS) previously used a fixed, publicly-known default marker: this class's own simple name, "EncodingPatternPreservation".
captureAndReplaceMatches() temporarily swaps matched content for this marker; restoreOriginalContent() restores it afterwards using replaceFirst(marker, ...), matching the marker as plain literal text, in FIFO order.
Because the marker is a known constant, input that already contains that literal string ahead of real matched content causes replaceFirst to match the attacker-supplied text instead of the real placeholder. Every subsequent restoration in the same call is then shifted by one, silently corrupting the output — restored content ends up in the wrong position (or is left as a raw, unrestored marker string).
Minimal repro:
I want to be precise about severity: I checked whether this is exploitable as an injection/XSS primitive and don't believe it is — the only regex currently fed through this class (CSSCodec's RGB-triplet pattern) can only ever capture digits, %, commas, whitespace and rgb(/), so a desynchronized restore can't smuggle unexpected characters through encodeForCSS(). This is an output-integrity bug (silently wrong/corrupted encoder output), not a bypass of the encoding itself.
Fix
Derive the default marker per-instance from a random UUID instead of a fixed literal, so it can't be predicted or pre-supplied in input. Hyphens are stripped from the UUID because a hyphen would itself be altered by an encoding pass (e.g. CSSCodec.encode() backslash-escapes non-immune characters) before restoreOriginalContent() runs, which would break the exact-match lookup — I hit this while writing the fix and confirmed it against the existing CSSCodecTest suite. The public setReplacementMarker() API is unchanged for callers who want to supply their own marker.
Test plan