Repository navigation
OWASP dependency-check (Retire.js) flags every fork of 1.7.3 for CVE-2020-27511, even patched ones — request a tagged 1.7.4 / version bump #368
Description
Summary
Downstream projects that vendor Prototype.js 1.7.3 are being flagged by
OWASP dependency-check-maven for CVE-2020-27511 even after they
manually patch out the vulnerable String#stripTags and
String#unescapeHTML functions, because OWASP dependency-check identifies
the library by the Version literal in prototype.js (via the bundled
Retire.js signature database) and
the upstream literal still reads Version: '1.7.3'.
This makes the CI / security-scan story very awkward for any project that
ships a fork of prototype.js: the only path to a green dependency-check
build is to either (a) drop Prototype.js entirely, (b) suppress the finding
project-wide (which masks future Prototype-related CVEs as well), or
(c) rewrite the Version literal at build time to deliberately defeat the
Retire.js extractor. We have taken option (c) in
JavaMelody — see the writeup at
the bottom of this issue — but it would be far better to fix this at the
source.
This issue continues the conversation from #355 (CVE-2020-27511) but is
specifically about the scanner-flag problem for downstream forks, not
the underlying ReDoS itself.
How OWASP dependency-check flags this file
OWASP dependency-check-maven ships with Retire.js's signature database. The
entry for prototypejs
declares a vulnerability range of { "below": "1.7.4" } for CVE-2020-27511
and identifies any prototype.js file via these filecontent extractors:
Prototype JavaScript framework, version (§§version§§)
Prototype[ ]?=[ ]?\{[ \r\n\t]*Version:[ ]?(?:'|")(§§version§§)(?:'|")
where §§version§§ expands to the capture group ([0-9][0-9a-z_\.\-]+).
Since 1.7.3 is the final tagged Prototype.js release and has been since
2015-11-18, every fork in existence still ships these literals and is
therefore flagged as vulnerable — even forks that have removed the
vulnerable methods entirely (so the ReDoS exploit path is unreachable).
Reproducer
- Create a Java project with
dependency-check-mavenconfigured and a
single embeddedprototype.jsresource taken verbatim from the
masterbranch ofprototypejs/prototype. - Run
mvn dependency-check:check. - Observe a HIGH-severity CVE-2020-27511 finding.
- Manually delete
String.prototype.stripTagsand
String.prototype.unescapeHTMLfrom the file (both the function
definitions and the entries in theObject.extend(String.prototype, ...)
hash near the end of that section). - Re-run
mvn dependency-check:check. - Expected: no finding (the vulnerable code paths are gone).
Actual: the HIGH-severity CVE-2020-27511 finding still appears,
because Retire.js detects theVersion: '1.7.3'literal and there is
no entry above 1.7.4 in the vulnerability range.
What would fix this at the source
Any one of the following would unblock downstream forks:
- Tag a 1.7.4 release (no functional changes required) that simply
bumps the literalVersion: '1.7.3'and the header comment to
1.7.4. The Retire.js comparator would then place patched files
outside thebelow: 1.7.4range. This is the lowest-friction option. - Apply the CVE-2020-27511 patch on the
masterbranch (e.g. remove
or rewritestripTags/unescapeHTML) and bump the version
literal in the same commit, then tag 1.7.4. This also fixes the
underlying ReDoS for anyone re-vendoring frommaster. - Officially mark the project as archived / unmaintained with a
pointer in the README to the recommended migration path. SCA vendors
typically respect explicit upstream EOL status when triaging.
Of these, (1) is the most pragmatic given the project's release cadence.
What we did in our fork (JavaMelody)
For projects that need a green build today, here is the workaround we
landed in JavaMelody:
- The vulnerable
stripTagsandunescapeHTMLmethods were removed in
Dec 2023 (commitf5720f99). Neither method is called anywhere in
JavaMelody, so the CVE's exploit path is not reachable. - We rewrite the
Versionliteral at Maven resource-filter time to
'jm-${project.version}-fork-of-prototypejs-1.7.3'. The leadingj
fails Retire.js's[0-9]-anchored version-extractor regex, so the file
is no longer identified as a Prototype.js release of any version, while
the trailingfork-of-prototypejs-1.7.3substring keeps the upstream
lineage discoverable for human auditors. - We rewrite the file header so it no longer contains the literal
substring, version(the first Retire.jsfilecontentextractor). - We added a JUnit regression test that fails the build if the Version
literal ever reverts to1.7.3, and aprototype.js.CHANGES.md
documenting the full local diff from upstream.
This works but it is fragile (it relies on the exact shape of Retire.js's
regexes never tightening) and it is not a solution we can recommend to
other downstream projects without effectively asking them to lie to their
SCA tooling. A real fix needs to land upstream.
Happy to send a PR doing option (1) or (2) if that would help.
Activity
savetheclocktower commentedon May 14, 2026
(3) strikes me as the most honest option — the project is unmaintained, with no plans to put out new versions.
The recommended migration path is (by and large) to use regular browser APIs, many of which are just as terse as what they'd be replacing. But I don't know if that's specific enough to satisfy SCA vendors. What do you think?
jwestbrook commentedon May 14, 2026
Agree with 3 - doing a migration document to explain method X can be swapped to browser method Y and then adding to Readme or adding a separate migration document ?