XSS bugs survive security code review because reviewers audit logic and structure first, then skim the parts where user input meets the DOM. By the time a reviewer has found one real issue worth commenting on, the attention budget is spent. The XSS surface sits just past that stopping point.
If you're reviewing frontend pull requests regularly, you've probably been there: you catch a null-check problem, leave a comment, scan the rest, and approve. The dangerouslySetInnerHTML call two lines below the null-check goes out untouched.
Where do XSS bugs hide in a pull request?
Three zones get the least scrutiny: template interpolation outside a framework's safe rendering path, event-handler props built from external data, and third-party component wrappers that strip sanitisation without advertising it.
The null-check example above is typical. A reviewer catches a real problem, marks the PR, and approves without reading the innerHTML line. Another common miss: an Angular component that bypasses DomSanitizer by passing a value through a pipe the reviewer doesn't recognise as unsafe. The pattern is consistent. Reviewers stop when they've found something, and the XSS surface sits just past that stopping point.
What are code vulnerabilities, and why does XSS count as one?
A code vulnerability is a flaw in source code that lets an attacker cause behaviour the author didn't intend. Cross-site scripting (XSS) is one of the most reliably exploitable frontend variants because browsers trust and execute whatever a page serves them.
XSS means an attacker injects a script into a page that another user's browser then runs, giving the attacker access to that user's session, cookies, or DOM. Stored XSS persists in a database and fires for every user who loads the infected view. Reflected XSS travels in a URL and fires once. DOM-based XSS never hits the server at all, which is why it slips past server-side scanners.
Frontend pull requests are the last human checkpoint before DOM-based XSS ships. Static analysis tools catch known patterns, but novel or framework-specific sinks often go undetected without a reviewer who knows what to look for.
What does it mean to write secure code in a frontend context?
Writing secure frontend code means treating every value that originates outside your own codebase as untrusted until it has been explicitly escaped or validated at the point it touches the DOM. That's the principle. The places it breaks down are worth naming.
Escaping at the sink, not the source
Sanitising input on arrival is useful, but the reliable rule is to escape at the output sink: the moment a value enters innerHTML, an attribute, a URL, or an eval-equivalent call. Input can pass through multiple functions before it reaches the DOM. Escaping at the source doesn't protect you if a later step undoes it.
Framework defaults and how they break
React escapes JSX interpolation by default. That protection disappears the moment a developer reaches for dangerouslySetInnerHTML, passes a user string to an href without a protocol check, or composes a style attribute from external data. The name dangerouslySetInnerHTML is a warning in plain text, but under review pressure it reads like any other prop.
The v-html and bypassSecurityTrustHtml traps
Vue's v-html and Angular's bypassSecurityTrustHtml are the equivalent escape hatches in those stacks. Both exist for legitimate reasons, both are reviewed too quickly, and both appear in real-world XSS post-mortems. If you see either in a PR, the review job is to confirm a sanitisation library, by name, stands between external data and that call.
How to do a security code review on a frontend PR
A security-focused frontend review follows a short, repeatable checklist rather than a general read-through. General read-throughs miss sinks because human attention follows logic, not data flow.
Build the data-flow picture first
Before reading line by line, trace where external data enters the component: props, route params, query strings, API responses, localStorage. Mapping the sources takes two minutes and tells you exactly which lines need scrutiny. If you skip this step, you're reading code without knowing which parts are load-bearing for security.
Check every sink against its escape guarantee
For each source you found, follow it to where it lands. If it reaches innerHTML, dangerouslySetInnerHTML, v-html, bypassSecurityTrustHtml, eval, document.write, or a URL attribute, confirm the value has been sanitised by a library you can name, not an ad-hoc string replace. A replace that strips script tags is not sanitisation. DOMPurify is sanitisation.
Flag the gaps, then approve deliberately
Leave a comment on any unescaped sink even if you believe the data is safe in the current flow. Data flows change. A comment creates an audit trail and signals to the next reviewer where the risk surface is. Approving without comment implies you checked and found it clean. What makes a code review comment actionable is a separate skill worth building alongside this checklist.
Why does practising on real pull requests build this skill faster than reading about it?
Reading about XSS tells you what to look for. Reviewing actual pull requests trains the pattern recognition that fires when you're under time pressure in a real security code review.
The gap between knowing a rule and catching a violation in unfamiliar code is closer to a motor skill than a knowledge gap. Developers who review dozens of real PRs across React, Vue, and Angular start to see the unsafe sink before they consciously reach for the checklist. That fluency only comes from repetition on real code, not from documentation. Code review skills that compound over a career follow exactly this pattern: the ones that stick are built through practice, not study.
Goodcatch is built around that idea. Each stack-specific track puts you through graded reviews on real pull requests, scores what you caught and what you missed, and surfaces your weak spots so you can see whether you're missing sinks in Vue but not React. The free trial runs in-browser with no account required.
How much does a security code review cost, and when is a tool the wrong choice?
The cost depends entirely on what you mean. A professional security audit or penetration test runs from hundreds to tens of thousands of dollars depending on scope. Tooling and self-study are a fraction of that.
Automated scanners like ESLint security plugins or Semgrep catch known XSS patterns cheaply and should run in CI regardless of what else you do. They're not a substitute for reviewer skill because they miss context-dependent and framework-specific sinks.
A practice tool like Goodcatch is the wrong choice if your team needs a formal penetration test or a compliance audit. It's aimed at developers who want to get better at catching issues themselves, not at replacing a security professional. Goodcatch's unlimited plan costs $19 per month or $144 per year and includes weak-spot analytics. The free tier gives you three graded reviews with no account, which is enough to judge whether graded practice fits your workflow.
Frequently asked questions
Is XSS only a problem in older codebases?
No. Modern frameworks reduce the surface area but don't eliminate it. React, Vue, and Angular all ship explicit escape hatches that developers reach for when they need to render HTML from an external source, and those hatches appear in current codebases regularly. The risk is framework-specific, not era-specific.
Do linters and CI tools replace a security-focused reviewer?
They reduce the risk of known patterns but don't replace reviewer judgment. Tools like Semgrep and ESLint security plugins work from fixed rule sets. A reviewer who understands data flow can catch a novel sink or a framework-specific bypass that no rule covers. Where Claude and similar AI tools miss real security issues follows the same logic: pattern matching and contextual judgment are different capabilities.
What security issues do junior developers miss most often?
Junior reviewers tend to miss sinks they haven't encountered before, especially framework-specific ones like bypassSecurityTrustHtml or v-html. They also tend to stop reviewing once they've found one issue, which is the stopping-too-soon pattern this post describes. Security issues junior developers most often miss in pull requests covers the full list.
Try a free graded review on Goodcatch and see which sinks you miss.