JS-1790 Restrict S5725 to statically versioned URLs#7134
JS-1790 Restrict S5725 to statically versioned URLs#7134pierre-loup-tristant-sonarsource wants to merge 2 commits into
Conversation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Agentic Analysis: Early ResultsAgentic Analysis and Context Augmentation are available on your project. Here are some issues that could have been prevented. Follow the links to learn how to put them into action. 10 issue(s) found across 1 file(s):
Analyzed by SonarQube Agentic Analysis in 2.5 s |
Ruling ReportCode no longer flagged (4 issues)S1441> 1 | // No issue - URL has no version path segment
2 | var script1 = document.createElement("script");
3 | script1.src = "https://www.googletagmanager.com/gtag/js?id=UA-XXXXX-X";S3504> 1 | // No issue - URL has no version path segment
2 | var script1 = document.createElement("script");
3 | script1.src = "https://www.googletagmanager.com/gtag/js?id=UA-XXXXX-X";S3798> 1 | // No issue - URL has no version path segment
2 | var script1 = document.createElement("script");
3 | script1.src = "https://www.googletagmanager.com/gtag/js?id=UA-XXXXX-X";S5725> 1 | // No issue - URL has no version path segment
2 | var script1 = document.createElement("script");
3 | script1.src = "https://www.googletagmanager.com/gtag/js?id=UA-XXXXX-X";New issues flagged (39 issues)S5725ant-design/site/theme/template/IconDisplay/IconPicSearcher.tsx:62 60 |
61 | loadModel = () => {
> 62 | const script = document.createElement('script');
63 | script.onload = async () => {
64 | await window.antdIconClassifier.load(); 10 |
11 | // Sensitive - versioned URL (semver path), missing integrity
> 12 | var script3 = document.createElement("script");
13 | script3.src = "https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js";
14 | script3.crossOrigin = "anonymous"; 16 |
17 | // Sensitive - versioned URL (package@version), missing crossorigin
> 18 | var script4 = document.createElement("script");
19 | script4.src = "https://cdn.jsdelivr.net/npm/jquery@3.7.1/dist/jquery.min.js";
20 | script4.integrity = "sha384-wHAiFfRlMFy6i5SRaxvfOCifBUQy1xHdJ/yoi7FRNXMRBu5WHdZYu1hA6ZOblgut"; 38 |
39 | // Sensitive - versioned URL with both integrity but crossOrigin is not "anonymous";
> 40 | var script7 = document.createElement("script");
41 | script7.src = "https://cdn.jsdelivr.net/npm/jquery@3.7.1/dist/jquery.min.js";
42 | script7.integrity = "sha384-wHAiFfRlMFy6i5SRaxvfOCifBUQy1xHdJ/yoi7FRNXMRBu5WHdZYu1hA6ZOblgut";S1192 17 | // Sensitive - versioned URL (package@version), missing crossorigin
18 | var script4 = document.createElement("script");
> 19 | script4.src = "https://cdn.jsdelivr.net/npm/jquery@3.7.1/dist/jquery.min.js";
20 | script4.integrity = "sha384-wHAiFfRlMFy6i5SRaxvfOCifBUQy1xHdJ/yoi7FRNXMRBu5WHdZYu1hA6ZOblgut";
21 | document.head.appendChild(script4); 18 | var script4 = document.createElement("script");
19 | script4.src = "https://cdn.jsdelivr.net/npm/jquery@3.7.1/dist/jquery.min.js";
> 20 | script4.integrity = "sha384-wHAiFfRlMFy6i5SRaxvfOCifBUQy1xHdJ/yoi7FRNXMRBu5WHdZYu1hA6ZOblgut";
21 | document.head.appendChild(script4);
22 | S1441 5 |
6 | // No issue - only API major version (v3 has no minor component)
> 7 | var script2 = document.createElement("script");
8 | script2.src = "https://js.stripe.com/v3/stripe.js";
9 | document.head.appendChild(script2); 6 | // No issue - only API major version (v3 has no minor component)
7 | var script2 = document.createElement("script");
> 8 | script2.src = "https://js.stripe.com/v3/stripe.js";
9 | document.head.appendChild(script2);
10 | 10 |
11 | // Sensitive - versioned URL (semver path), missing integrity
> 12 | var script3 = document.createElement("script");
13 | script3.src = "https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js";
14 | script3.crossOrigin = "anonymous"; 11 | // Sensitive - versioned URL (semver path), missing integrity
12 | var script3 = document.createElement("script");
> 13 | script3.src = "https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js";
14 | script3.crossOrigin = "anonymous";
15 | document.head.appendChild(script3);...and 29 more 📋 View full reportCode no longer flagged (4)New issues flagged (39)
|
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
Code Review 👍 Approved with suggestions 0 resolved / 2 findingsRestricts rule S5725 to statically versioned URLs to reduce false positives. Consider revising the empty string handling for crossOrigin and tightening the ALIAS_PATH_REGEX to avoid unintended pattern matches. 💡 Edge Case: crossOrigin="" (empty string) treated as missing crossOrigin📄 packages/analysis/src/jsts/rules/S5725/rule.ts:107-113 In the HTML DOM spec, setting This is an edge case that could affect real-world code where developers use the empty string form. Also accept empty string as equivalent to 'anonymous' per the HTML spec💡 Edge Case: ALIAS_PATH_REGEX may match non-version @ patterns in URLs📄 packages/analysis/src/jsts/rules/S5725/rule.ts:32 The regex
While unlikely in practice for CDN URLs, requiring at least one digit would make the regex more robust: Require at least one leading digit after @ to avoid matching dot-only or non-version patterns🤖 Prompt for agentsOptionsAuto-apply is off → Gitar will not commit updates to this branch. Comment with these commands to change:
Was this helpful? React with 👍 / 👎 | Gitar |
vdiez
left a comment
There was a problem hiding this comment.
Looks good overall.
Non-blocking follow-ups if we want to tighten a couple of edge cases later:
crossOriginis currently treated order-insensitively, soscript.crossOrigin = anonymous; script.crossOrigin = use-credentials;no longer raises even though the final value is not compliant.- The new version regexes do not match prerelease semver URLs such as
https://cdn.jsdelivr.net/npm/react@19.0.0-rc.1/umd/react.production.min.js, so those pinned URLs are currently skipped.
I would keep UUID-shaped URLs out of the heuristic for now unless we can point to a concrete JS/CDN pattern we want to support. In the current ruling corpus the UUID-looking URLs I checked are mostly opaque asset paths rather than versioned script artifacts, so matching them generically looks likely to reintroduce false positives.




Summary
/3.7.1/,/jquery@3.7.1/,/bootstrap@5.3.0, etc.), eliminating false positives on dynamic CDN URLs (Google Tag Manager, Stripe, etc.)integrityandcrossorigin="anonymous"attributes with distinct messages for each missing casecrossorigincheck when the assigned value cannot be statically resolved, avoiding false positivesTest plan
crossOrigin, and all three message variantscustom-jstsandant-designexpected files updated🤖 Generated with Claude Code