SPARK-843491: Remediate 8 High security findings in components - #862
Draft
mkesavan13 wants to merge 1 commit into
Draft
SPARK-843491: Remediate 8 High security findings in components#862mkesavan13 wants to merge 1 commit into
mkesavan13 wants to merge 1 commit into
Conversation
Jira: https://jira-eng-gpk2.cisco.com/jira/browse/SPARK-843491 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
COMPLETES #SPARK-843491
This pull request addresses
Remediates 8 unique High-severity security findings (UF-001 through UF-008) identified in the
webex/componentsrepository via Codeguard and workflow security harness scans (scan date: 2026-07-06, commit: b4f087a). Findings span client-side trust boundaries: URL validation, OpenUrl sink, OAuth CSRF state + token storage, prototype pollution, markdown HTML sanitization, and CI supply chain.Root Cause (per finding):
isValidUrl(src/util.js) checked only the URL protocol; no host/loopback allow-list was enforced forhttp:/https:URLs.window.open(data.url, '_blank')inuseActionOpenUrl.jslacked thenoopener,noreferrerfeature string.Uint8Array(4)) and never stored before opening the auth window.secureflag;SameSite=Strictwas absent.sessionStorage/localStoragestored the raw access token; the destructuredttlvalue was never applied.deepMergeinsrc/util.jsiteratedObject.entries(src)with no guard against__proto__,constructor, orprototypekeys.markdownIt.render()output was injected viadangerouslySetInnerHTMLwith no HTML sanitizer.npm install(non-deterministic) without an audit gate before release/build steps.by making the following changes
src/util.js—isValidUrl: addsisBlockedHosthelper that blocks loopback (localhost,127.x,[::1]), link-local (169.254.x,fe80::), and private/unique-local ranges forhttp:/https:URLs;data:URIs are unaffected.deepMerge: addsFORBIDDEN_MERGE_KEYSset (__proto__,constructor,prototype) to skip those keys.src/components/adaptive-cards/hooks/useActionOpenUrl.js— Passes'noopener,noreferrer'towindow.open.src/components/SignIn/SignIn.jsx— CSRF state: 16-bytecrypto.getRandomValues→ hex string, stored incsrfStateRefbefore auth window opens. Cookie: addsSameSite=Strict. Session/local storage: stores{token, expiry}JSON envelope with TTL instead of raw token.src/components/adaptive-cards/Markdown/Markdown.jsx— WrapsmarkdownIt.render()output withDOMPurify.sanitizebeforedangerouslySetInnerHTML.package.json— Addsdompurify ^3.4.13as a runtime dependency..circleci/config.yml— Replacesnpm installwithnpm ci; addsnpm audit --audit-level=highstep gating all downstream jobs..github/workflows/npm-storybook-release.yml— Replacesnpm installwithnpm ci; addsnpm audit --audit-level=highstep gating thenpx semantic-releasestep that holdsNPM_TOKEN/GITHUB_TOKEN.ai-docs/SECURITY.md— Updates Input Validation posture to documentisValidUrlhost blocking and DOMPurify layer (spec-currency).src/components/ai-docs/components-spec.md— UpdatesSignInandMarkdownentries for CSRF state generation/storage and DOMPurify (spec-currency).New test files:
src/util.test.js,src/components/SignIn/SignIn.test.jsx,src/components/adaptive-cards/Markdown/Markdown.test.jsx,src/components/adaptive-cards/hooks/useActionOpenUrl.test.js.Change Type
The following scenarios were tested
The testing is done with the amplify link
Unit tests added covering all independently testable findings (AC-1 through AC-7, 32 targeted tests across 4 new test files).
Gate 1 (compile:
npm run build): PASSED — ESM and UMD bundles built successfully.Gate 2 (unit-test:
NODE_ENV=test npm run test): PASSED — 262 tests, 18 suites, 107 snapshots all passing.Gate 3: Not run.
Testing
npm run build) passed; Gate 2 (unit-testNODE_ENV=test npm run test) passed — 262 tests, 18 suites, 107 snapshots; Gate 3 not run.Acceptance Criteria
isValidUrlblocks loopback, link-local, and private-range hosts forhttp:/https:URLs.src/util.test.js— all passing in Gate 2Action.OpenUrlopens withnoopener,noreferrerand rejects disallowed hosts/schemes.useActionOpenUrl.test.js— all passing in Gate 2SignIn.test.jsx— all passing in Gate 2SameSite=Strictalongsidesecureflag.SignIn.test.jsx— passing in Gate 2{token, expiry}envelope usingttl; no raw unbounded token write.SignIn.test.jsx— passing in Gate 2deepMergeskips__proto__,constructor, andprototypekeys.src/util.test.js— all passing in Gate 2markdownIt.render()output is wrapped withDOMPurify.sanitizebeforedangerouslySetInnerHTML.Markdown.test.jsx— all passing in Gate 2npm ciwithnpm audit --audit-level=highas a required gate..circleci/config.ymland.github/workflows/npm-storybook-release.ymlinspected — release-blocking enforcement is CI-ownedExternal Validation Required
AC-3 — OAuth CSRF state is generated with >=16 bytes of entropy, serialized as hex/base64url, stored, and validated so mismatched or missing state on return is rejected.
external-dependencySignIn.jsx:53-112opens a cross-origin popup, pollsnewWindow.closed, and calls callergetAccessToken()with nopostMessage/location reader, so no in-repo test drives it. Validator: app team owningredirectUricompares returned state to the stored value and aborts on mismatch/absence. Uncertainty: JiraToPr cannot enforce the host-side check.statethat does not match the stored value (or carrying nostate) does not complete sign-in; a matchingstateproceeds normally.AC-8 — Both CI configurations use 'npm ci' for deterministic installs and enforce an 'npm audit --audit-level=high' gate that blocks the release on high-severity findings.
ci-pipelinenpm ci+npm audit --audit-level=highcontent is inspectable via UT-8 (.circleci/config.yml) and UT-9 (release workflow), but these are config-inspection targets, not jest unit tests, and the release-blocking guarantee only manifests when CI runs. Validator: release owners run both pipelines; a high-severity audit finding must fail before the token-holding release. Uncertainty: JiraToPr cannot run CI; validate against the existing lockfile first.Contract Discovery Warnings
AI Assistance
Checklist before merging
Jira: https://jira-eng-gpk2.cisco.com/jira/browse/SPARK-843491