CVE Remediation in iTwin.js
This skill covers the domain knowledge for fixing security vulnerabilities in the iTwin.js Rush monorepo. It is referenced by the CVE audit agent, the merge-conflict-resolving skill, and the backport-resolution skill.
Key Files
| File | Purpose |
|---|---|
common/config/rush/pnpm-config.json |
Global dependency overrides and audit exceptions |
common/config/rush/pnpm-lock.yaml |
Resolved dependency tree (never manually edit) |
common/config/rush/common-versions.json |
Rush version-consistency policy (preferredVersions) |
common/config/rush/repo-state.json |
Auto-generated hash of repo state (commit alongside common-versions.json) |
<package>/package.json |
Direct dependency version ranges per package |
pnpm-config.json Structure
This file has two conflict-prone sections:
globalOverrides
Forces specific dependency versions across the entire monorepo. Used when a transitive dependency cannot be updated via its parent's semver range.
{
"globalOverrides": {
"<package>": "<patched-version>",
"<package>@<range>": "<patched-version>"
}
}
Each override should include a trailing comment with:
- The advisory URL (GHSA or CVE link)
- The dependency path that pulls in the vulnerable package
Illustrative example (always consult the current common/config/rush/pnpm-config.json before editing):
"globalOverrides": {
"rollup-plugin-copy>globby": "^11.0.0", // https://github.com/vladshcherbin/rollup-plugin-copy/issues/77
"elliptic": "^6.6.1", // https://github.com/advisories/GHSA-vjh7-7g9h-fjfh crypto-browserify>browserify-sign>elliptic
"fast-xml-parser": "^5.3.6", // https://github.com/advisories/GHSA-jmr7-xgp7-cmfj @google-cloud/storage > fast-xml-parser
"axios@<1.0.0": "^1.13.5", // https://github.com/advisories/GHSA-43fc-jf86-j433
"serialize-javascript": "^7.0.3" // https://github.com/advisories/GHSA-5c6j-r48x-rmvq mocha>serialize-javascript
}
Important: This file uses JSONC (JSON with comments). The last entry in any object/array must NOT have a trailing comma. When adding entries, ensure the previously-last entry gets a comma added and the new last entry does not have one.
ignoreCves (Audit Exceptions)
Located under a nested path. Used only for dev-tooling dependencies with no production path.
{
"unsupportedPackageJsonSettings": {
"pnpm": {
"auditConfig": {
"ignoreCves": [
"CVE-XXXX-XXXXX" // https://advisory-url — dev-only reason
]
}
}
}
}
Fix Strategy (Strict Order)
Always attempt fixes in this order. Do not skip to overrides without trying the earlier steps.
1. Classify: Direct vs Transitive
- Direct: The vulnerable package is listed in a project's
package.json - Transitive: The vulnerable package is pulled in by another dependency
2a. Direct Dependency Fix
- Update the version range in the affected
package.json - Run
rush updatethenrush auditto verify - If no safe version range exists, fall through to globalOverride (document why)
2b. Transitive Dependency Fix
- Check existing overrides first: Before adding a new override, check if the package already has an entry in
globalOverridesinpnpm-config.jsonto avoid conflicts or duplicates. - Semver range update (try first): Update the direct parent's
package.jsonrange to a version that resolves the transitive dep to a patched release - Scoped globalOverride (last resort): Only if no safe parent version exists. Scope the override to only the vulnerable version range (e.g.,
"lodash@>=4.0.0 <=4.17.23": "^4.18.0") rather than overriding all versions blanket. This avoids interfering with future already-patched versions. Document why in the override comment.
Use rush-pnpm why <package> to trace transitive dependency paths when the audit output truncates them.
3. ignoreCves (Absolute Last Resort)
Only for non-production/dev-tooling risk. Requires:
- Explicit rationale in comment
- Advisory link
- Confirmation that the dependency has no production code path
Never ignore a Critical/High production-path CVE when a patch is available.
Severity Policy
| Severity | Action |
|---|---|
| Critical | Always fix or explicitly document blocker and risk |
| High | Fix unless unacceptable breakage; if deferred, create tracking issue |
| Moderate/Low | Defer and create tracking issue with recommendation |
Validation Workflow
After any remediation change:
rush update # Regenerate lock file
rush audit # Verify CVE is resolved (internally runs rush-pnpm audit --audit-level high)
rush build # Ensure no build breakage
rush test # Ensure no test regressions
Note: rush audit does not accept --level or --json flags directly. Use rush-pnpm why <package> to investigate specific dependency paths.
When direct dependency version ranges were changed in a package.json:
rush extract-api # Check for API surface changes
Skip extract-api only when the sole change is a globalOverride in pnpm-config.json.
Rush Change Files
After remediation, Rush requires changelog entries:
# Check if change files are needed
rush change --verify -b origin/<base-branch>
# If needed for internal dependency-only updates, create blank entries non-interactively
rush change --bulk --message "" --bump-type none -b origin/<base-branch>
Change files land in common/changes/@itwin/<package>/ as JSON files with unique filenames.
common-versions.json
If a direct dependency bump triggers Rush consistency errors, update common/config/rush/common-versions.json to align versions. Always commit the auto-generated common/config/rush/repo-state.json hash update alongside it.