131. How would you respond to a compromised frontend dependency in production?
A transitive package in the build has been confirmed to exfiltrate form data from released bundles. Define containment, affected-version and route identification, build and artifact verification, traffic blocking, credential and session response, removal or pinning, clean rebuild, cache and service-worker invalidation, monitoring, user communication, and forensic preservation. Then design provenance, lockfile, review, integrity, sandboxing, secret-minimization, and rollout controls that reduce recurrence without claiming scanners alone prevent supply-chain attacks.
I would treat it as an active incident: contain exposure, identify every affected release and route, preserve evidence, restrict exfiltration where possible, protect credentials and sessions, remove the package, rebuild from trusted inputs, invalidate stale delivery paths, verify artifacts, monitor recovery, communicate appropriately, and strengthen supply-chain controls.
A harmful piece of software used by the website has already reached users and is secretly sending information away. The job is to stop further harm quickly, find every website version and page that contains it, protect people whose information may have been exposed, replace the bad software safely, and make sure old copies cannot keep running. I would also keep evidence so the cause can be investigated. Finally, I would improve how outside software is selected, checked, released, and monitored so a similar problem is less likely to reach users again.
- Which production releases, deployment regions, routes, and asset versions are currently suspected or confirmed to contain the compromised package?
- What data was the malicious package observed collecting, and which external destinations or domains received it?
- Do we have immutable build records, lockfiles, source commits, artifact hashes, dependency manifests, CDN logs, and deployment history for the affected releases?
- Does the application use service workers, long-lived CDN caching, or offline assets that could continue serving the compromised bundle after a normal deployment?
- Which credentials, sessions, tokens, or user actions could have been exposed through the affected forms?
- What incident-response, legal, privacy, and customer-notification processes already exist?
I would treat the confirmed dependency compromise as an active supply-chain incident. Released JavaScript executes in the user's browser with the capabilities available to the application origin, so malicious code that is already exfiltrating form data requires immediate containment before a complete root-cause investigation.
I would stop deploying builds that contain the dependency and freeze unrelated production changes so the response remains traceable. If a known-safe prior release exists, I would consider an emergency rollback. Otherwise, I would prepare the smallest safe replacement deployment that removes the malicious code.
I would disable an affected feature or separately loaded third-party script immediately when that can reduce exposure safely. If the package has already been bundled into first-party JavaScript, however, disabling a package registry version does not remove code from bundles users already downloaded. Those deployed assets must be replaced.
For traffic blocking, I would distinguish controls we actually have. If exfiltration goes through our own API, proxy, CDN, or other infrastructure, I can block the corresponding requests there. If the malicious JavaScript sends directly from users' browsers to an external attacker-controlled domain, our normal server edge cannot generally intercept that outbound browser traffic. I can remove the malicious code and send a stricter Content Security Policy, such as a restricted connect-src directive, on subsequent document loads. Corporate DNS or network-proxy blocking is useful only when we control the clients' network. I would not claim any of these controls can recall JavaScript that is already executing in an open tab.
I would map the compromised transitive package version to exact lockfile entries, build records, source commits, release IDs, chunk hashes, and deployment timestamps. Because it is transitive, I would also identify the direct dependency that introduced it and the complete dependency path.
Then I would determine which production routes actually load affected chunks. Route-level code splitting means one compromised package can appear only on certain pages or interactions. I would use build manifests, securely retained source maps if available, asset manifests, CDN logs, release metadata, and application telemetry to establish which users and routes could have executed the code.
I would not use today's local node_modules tree as evidence for an older release. Historical production artifacts must be traced from their own build records.
Before replacing evidence, I would preserve affected bundles, lockfiles, package metadata, package tarball identifiers where available, build logs, CI logs, dependency manifests, source commits, artifact hashes, deployment metadata, relevant CSP reports, CDN records, and network or application logs.
I would record timestamps and chain-of-custody information according to the organization's incident process. Logs should contain useful release IDs, route identifiers, asset hashes, and security-event metadata without storing passwords, authorization tokens, full session identifiers, or sensitive form contents.
Preserving evidence matters because immediately deleting workspaces, caches, or build artifacts can destroy information needed to establish how the compromise entered production.
I would calculate cryptographic hashes of affected production assets and compare them with trusted build records or previously recorded artifact hashes where such records exist. This helps distinguish a malicious dependency that entered during the normal build from a later unauthorized artifact modification.
I would also inspect the generated bundles or dependency metadata to verify that the malicious package code is actually present in the releases we classify as affected. Package-manager state alone does not prove which code was shipped to users.
I would identify what the malicious JavaScript could read or cause the browser to send. It may access form fields, DOM data, JavaScript-readable storage, client configuration, and tokens deliberately exposed to JavaScript.
HttpOnly cookies are different: JavaScript cannot directly read their values. However, malicious same-origin JavaScript may still issue authenticated requests because the browser can attach eligible cookies automatically. Therefore, HttpOnly reduces token theft but does not make an authenticated session harmless after arbitrary first-party script execution.
If passwords, reusable tokens, API credentials, payment information, or other sensitive data were exposed, I would coordinate appropriate reset or rotation. If an attacker could abuse affected authenticated sessions, I would revoke those sessions or require reauthentication according to the demonstrated exposure and business risk.
Authentication and authorization are separate. Authentication establishes identity. Authorization decides what that identity may do. The trusted server must enforce authorization for every protected operation; frontend state must never be treated as an authorization boundary.
I would remove the dependency if the application can function safely without it. If it is required, I would move to a version independently confirmed to be safe.
For a transitive package, a package-manager override or resolution mechanism may be an appropriate emergency mitigation to force a reviewed safe version. I would make that change explicit, code-reviewed, tested, and documented rather than silently altering dependency resolution.
I would commit the corrected lockfile and review the dependency diff. A lockfile improves deterministic dependency resolution, but it does not prove that the locked package is trustworthy. A malicious release can be locked perfectly.
I would avoid rebuilding from an existing developer workspace, dependency directory, package cache, or CI worker that might itself contain compromised material unless that environment has been investigated and cleared.
I would use a clean trusted builder, the reviewed source commit, the corrected lockfile, and trusted package inputs. Where the package manager supports strict lockfile installation, I would use it so dependency resolution cannot drift silently during the emergency rebuild.
The build should produce immutable artifacts. I would record the source commit, dependency metadata, builder identity or attestation where supported, artifact hashes, and provenance information so we can show what inputs produced the replacement release.
Where reproducible builds are practical, reproducing the output independently provides additional confidence. I would not assume every frontend toolchain is perfectly reproducible without testing that property.
Deploying a safe bundle is not sufficient if old content still points users to compromised assets.
I would purge affected CDN entries that we control, especially HTML documents, manifests, bootstrap files, or non-content-hashed assets that can reference compromised chunks. With content-hashed filenames, the safe rebuild should normally produce new asset URLs, but stale HTML can still reference an old compromised URL.
A normal web application cannot directly erase every browser's ordinary HTTP cache on command. Instead, I would ensure new documents reference safe content-hashed assets and use appropriate cache policies for mutable entry documents so clients receive the corrected references.
If a service worker cached the compromised assets, I would release a known-safe service-worker version that updates its cache names or manifest, removes obsolete compromised entries during activation where appropriate, and serves only approved assets. In a severe incident, an emergency service-worker strategy may use skipWaiting and clients.claim when the resulting lifecycle behavior has been reviewed carefully. Those APIs accelerate activation but can also change running pages underneath existing clients, so they are a tradeoff rather than a universal default.
I would test both a fresh browser and an existing profile already controlled by the old service worker. Offline clients that do not reconnect cannot receive remediation until they reconnect, so monitoring must account for that limitation.
I would verify that production HTML, manifests, and route chunks reference approved assets only. I would compare deployed artifact hashes with the trusted clean build and confirm that the compromised package or code is absent from the replacement dependency graph and bundles.
I would exercise every affected route and interaction and inspect browser network activity to confirm the observed exfiltration behavior has stopped. I would verify the replacement service worker, CDN behavior, session flows, CSP behavior, and functionality previously supplied by the removed package.
Safe failure matters. If a risky third-party capability cannot be restored safely, I would disable that feature rather than silently loading an unverified fallback.
I would monitor for requests to confirmed attacker-controlled destinations where telemetry can observe them, continued requests for old compromised asset hashes, stale service-worker versions, unexpected network destinations visible through CSP reporting or application telemetry, suspicious authenticated behavior, and API patterns associated with the compromise.
I would keep monitoring through the period in which stale clients can reasonably remain active. A deployment completing successfully does not mean every browser instantly stops running previously downloaded code.
I would avoid collecting sensitive form values merely to prove that exfiltration stopped. Monitoring should use metadata and controlled test accounts where possible.
I would maintain an incident timeline that separates confirmed facts from assumptions. Engineering, security, incident response, privacy, legal, product, and support teams should share a consistent understanding of affected releases, exposure windows, mitigations, user impact, and remaining uncertainty.
If affected users need to reset passwords, reauthenticate, monitor accounts, or take another protective action, the communication should clearly explain what is known, who is affected when that can be determined, what has been fixed, and what users should do next. I would follow the organization's legal and regulatory notification process rather than inventing notification thresholds myself.
After containment, I would determine how the malicious package reached the build. Investigation areas might include a compromised upstream maintainer, malicious package release, dependency confusion, registry-account compromise, unsafe installation scripts, CI compromise, unauthorized lockfile changes, or another supply-chain path.
Those are hypotheses, not conclusions. I would name the cause only when the evidence supports it.
The investigation should establish the first malicious package version, dependency path, first affected build, first affected deployment, affected routes, data-access behavior, exfiltration destination, exposure period, and why existing controls did not prevent or detect the incident earlier.
Provenance means evidence showing where software came from and how it was built. Where ecosystem support exists, I would prefer packages and internal artifacts with verifiable publishing or build provenance.
For our own releases, I would retain the source commit, lockfile, dependency manifest, builder identity or attestation, artifact hashes, and deployment identity. Cryptographically verifiable provenance can make unauthorized substitutions easier to detect and gives incident responders stronger evidence about artifact origin.
Provenance does not prove that source code is safe. A legitimately published package can still contain malicious code.
I would keep lockfiles committed and require dependency and lockfile changes to go through review. Automated update tools are useful for producing small, visible upgrades, but high-risk dependency changes should still receive human judgment.
For important dependencies, I would review publisher or ownership changes, unexpected new install scripts, unusual release activity, new transitive packages, significant permission or capability changes, and large unexplained code differences where practical.
I would reduce unnecessary dependencies because every dependency adds maintenance and supply-chain exposure. I would not blindly rewrite mature libraries merely to reduce package count, because a poorly implemented replacement can introduce different vulnerabilities.
For separately hosted third-party scripts, Subresource Integrity can allow the browser to verify that a fetched script or stylesheet matches an expected cryptographic hash. For cross-origin resources, the resource must also satisfy the browser's CORS requirements for SRI validation.
SRI does not protect an application bundle that already incorporated malicious dependency code during the build. It also does not tell us whether the expected bytes themselves are benign.
Package-manager lockfiles can contain integrity metadata that helps verify downloaded package bytes against the recorded package artifact. Again, matching expected bytes is an integrity property, not a malware guarantee.
If a third-party capability does not require direct access to the main application's DOM or JavaScript context, I would consider placing it in a sandboxed iframe with only the minimum sandbox permissions necessary.
The exact sandbox flags matter. For example, combining powerful permissions carelessly can undermine the intended isolation, especially for same-origin content. I would design the iframe's origin and permissions deliberately and expose only a narrow validated message interface when cross-context communication is required.
This approach cannot isolate ordinary npm libraries that must execute directly inside the application bundle, so sandboxing is useful only for suitable features rather than being a universal dependency defense.
I would never ship server secrets, private signing keys, database credentials, or long-lived privileged credentials in frontend JavaScript. Anything delivered to a browser should be treated as observable and potentially reachable by compromised first-party JavaScript.
For cookie-based sessions, Secure, HttpOnly, and an appropriate SameSite policy provide useful protections. HttpOnly prevents direct JavaScript reads, Secure restricts cookie transmission to secure transport, and SameSite can reduce some cross-site request risks. None of these makes arbitrary malicious same-origin JavaScript safe.
I would minimize sensitive values placed in the DOM, JavaScript-accessible browser storage, client configuration, and logs. Data that the browser does not need should remain on the trusted server.
A restrictive CSP can limit script sources and network destinations. Trusted Types can reduce dangerous DOM-based injection paths by requiring trusted values for supported DOM sinks. For untrusted text, I would prefer textContent, createTextNode, safe DOM APIs, or normal framework escaping instead of innerHTML. If the product intentionally accepts HTML, I would use a well-maintained sanitizer appropriate for that HTML context rather than treating generic input filtering as complete protection.
These controls are valuable for XSS and limiting some consequences of injected or third-party code, but they do not make a malicious first-party dependency trustworthy. Code legitimately executing in the application's own bundle can often use capabilities the application itself requires.
The same distinction applies to other browser controls. Same-origin policy and CORS primarily restrict cross-origin access; they do not protect data from malicious JavaScript already executing within the application's origin. CSRF defenses address cross-site request forgery and generally cannot be relied upon to stop arbitrary JavaScript already executing in the trusted page, because that script may access the same tokens and application APIs available to legitimate code.
Clickjacking defenses such as frame-ancestors or X-Frame-Options may still be appropriate for the application, but they do not directly solve this dependency compromise. I would keep the response focused on controls that change the supply-chain incident's risk.
For dependency changes whose risk justifies it, I would use staged or canary rollout instead of immediately exposing every user. I would observe functional failures, unexpected asset behavior, security telemetry, CSP reports, and new network destinations before widening the release.
Promotion should use immutable artifacts so the exact artifact validated in an earlier stage is the one promoted to a larger population rather than rebuilding it differently for each environment.
I would maintain a fast rollback mechanism, but a rollback artifact must be independently known to be safe. Rolling back to an older release that contains the same compromised transitive dependency merely reintroduces the incident.
Dependency scanners are useful for known vulnerabilities, known malicious packages, suspicious package metadata, and other detectable signals. They should run continuously and their findings should be reviewed according to risk.
But scanners cannot guarantee detection of a newly compromised maintainer, a previously unknown malicious release, a poisoned build process, a malicious package that has not yet been classified, or an authorized package version containing intentionally harmful behavior.
I would therefore use scanners as one layer among provenance, deterministic dependency resolution, dependency review, trusted clean builds, artifact verification, least privilege, appropriate isolation, secret minimization, browser defenses, staged rollout, monitoring, and incident-response readiness.
The practical sequence is: contain exposure, scope the exact released artifacts and routes, preserve evidence, protect affected users, remove the malicious dependency, rebuild from trusted inputs, eliminate stale delivery paths, verify production behavior, monitor recovery, communicate confirmed impact, complete root-cause analysis, and strengthen controls so the next dependency compromise is harder to ship and easier to detect.
- Declare an active security incident and freeze unsafe releases.
- Stop or reduce exposure by disabling affected functionality, replacing affected assets, or rolling back only to a release proven safe.
- Restrict confirmed exfiltration paths using controls that actually apply: block requests in infrastructure we control, update CSP for new document loads, and use DNS or proxy blocking only for managed client networks.
- Trace the transitive package to exact lockfiles, builds, releases, chunks, routes, and exposure timestamps.
- Preserve compromised bundles, package metadata, hashes, logs, and deployment records before cleanup.
- Determine which user data, credentials, tokens, sessions, or authenticated actions were exposed and apply proportionate resets, rotations, or revocation.
- Remove the dependency or pin or override it to an independently verified safe version.
- Rebuild in a clean trusted environment using reviewed source and dependency inputs.
- Record and verify artifact hashes and provenance.
- Deploy new approved assets and invalidate stale CDN, HTML, manifest, and service-worker delivery paths.
- Test both fresh and previously cached browser states across every affected route.
- Monitor old asset hashes, stale service workers, attacker destinations, suspicious sessions, and related API behavior.
- Communicate confirmed impact and required user actions.
- Complete root-cause analysis.
- Strengthen provenance, lockfile review, dependency review, integrity controls, isolation, secret minimization, staged rollout, and safe rollback.
The main cost is operational rather than algorithmic. Engineers may need to inspect many dependency trees, historical builds, bundles, routes, environments, caches, service workers, user sessions, and logs. Work grows with the number of releases and users that could be affected. Clean rebuilds, cache purges, session revocation, and staged releases can temporarily slow delivery or inconvenience users. Stronger provenance, review, integrity checks, immutable artifacts, and canary rollouts add ongoing CI and maintenance work, but they reduce uncertainty and make future compromises easier to contain, verify, and investigate. Browser memory usage is not the important cost in this incident; operational investigation and safe deployment dominate.
This question tests whether the candidate can manage a real frontend supply-chain compromise instead of treating dependency security as only a scanner problem. The interviewer is evaluating containment, release and artifact tracing, browser-specific cache behavior, credential and session response, trusted rebuild practices, forensic preservation, monitoring, user communication, and long-term controls such as provenance, lockfiles, integrity verification, sandboxing, secret minimization, and safe rollout.
Common mistakes are treating the incident as solved after changing package.json; checking only the current dependency tree instead of historical released artifacts; assuming a package-registry takedown removes code already bundled into production; claiming the application's server edge can generally block direct browser traffic to an external attacker domain; deleting evidence before preserving it; rebuilding on a potentially contaminated workspace or CI worker; forgetting stale HTML, lazy-loaded chunks, CDN entries, and service-worker caches; claiming every browser cache can be remotely erased; assuming HttpOnly cookies make authenticated sessions completely safe; rotating credentials without considering actual exposure; relying only on CSP, CORS, SRI, lockfiles, or dependency scanners; treating provenance as proof that source code is benign; rolling back to another affected release; logging sensitive form data or tokens during investigation; and failing to test browsers that already contain old cached assets or service workers.
Present the response in incident order: contain, scope, preserve evidence, protect users, remove the dependency, rebuild cleanly, invalidate every stale delivery path you control, verify, monitor, communicate, and then prevent recurrence. Be precise about browser limitations: you cannot recall JavaScript already executing in an open tab, remotely erase every normal browser cache, or rely on scanners and lockfiles to prove a dependency is safe.



