codeql icon indicating copy to clipboard operation
codeql copied to clipboard

General issue: XSS vulnerabilities (CWE-79/CWE-116) not detected in React/Next.js .tsx components

Open aniakowalewska1 opened this issue 1 month ago • 2 comments

Description I am testing the CodeQL accuracy by seeding different types of XSS vulnerabilities and running the advanced workflow with security-extended and security-and-quality queries. I noticed an issue with CodeQL flagging vulnerabilities in .tsx files. While the seeded code is detected as expected in route.ts, it is not in the component files. In both cases, at least CWE-79 should be noted.

Setup

  • GitHub Advanced Security enabled on a public test repo
  • Language: typescript
  • Framework: Next.js
  • CodeQL initialized with codeql/javascript-queries and security-extended,security-and-quality

Workflow file

name: "CodeQL Advanced"

on:
  push:
    branches: ["main", "security/*"]
  pull_request:
    branches: ["main", "dev"]

jobs:
  analyze:
    name: Analyze (${{ matrix.language }})
    runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }}
    
    permissions:
      security-events: write
      packages: read
      actions: read
      contents: read

    strategy:
      fail-fast: false
      matrix:
        include:
          - language: actions
          - language: javascript-typescript
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Initialize CodeQL
        uses: github/codeql-action/init@v4
        with:
          languages: ${{ matrix.language }}
          queries: security-extended,security-and-quality
          packs: codeql/javascript-queries

      - name: Perform CodeQL Analysis
        uses: github/codeql-action/analyze@v4
        with:
          category: "/language:${{matrix.language}}"

Reference https://github.com/aniakowalewska1/migration-playground/pull/39

Expected CWEs that are not detected, but are present in documentation (https://codeql.github.com/codeql-query-help/javascript-cwe/) CWE-79

export default function Seed({ msg }: { msg: string }) {
  return (
    <div>
      <h3>Seed XSS page</h3>
      <div dangerouslySetInnerHTML={{ __html: msg }} />
    </div>
  );
}

CWE-20/CWE-116

export async function getServerSideProps(context: GetServerSidePropsContext) {
  const { query } = context;
  const msg = query?.msg ?? "";
  return { props: { msg } };
}

CWE-79

export default function TestPage({ userInput }: TestPageProps) {
  return <XssSeed userContent={userInput} />;
}

CWE-20/CWE-601

export async function getServerSideProps(context: GetServerSidePropsContext) {
  return { props: { userInput: context.query.content || "" } };
}

CWE-79

<div
  dangerouslySetInnerHTML={{ __html: userInput }}
  data-testid="seed-xss-sink"
/>

CWE-116

  const userInput =
    userContent || "<img src=x onerror=\"console.error('xss')\">Hello</img>";

Questions

  • Is there additional setup needed for scanning React?
  • Why is CWE-79 and CWE-116 flagged is a .ts file and ignored in .tsx?

aniakowalewska1 avatar Nov 17 '25 09:11 aniakowalewska1

Thanks for the report. I was able to locally reproduce the CWE-079/ReflectedXss alert on your PR. It's not immediately clear to me why the XSS in that file is getting picked up by the query but not the ones in .tsx files. They do follow different patterns (GET/NextResponse vs React component-based page), but I don't think that should matter. I'll bring in another team that can help.

d10c avatar Nov 18 '25 16:11 d10c

Hi @aniakowalewska1,

Thanks for the report. This was due to a bug in the Next.js model. I've opened a PR to fix this.

With the above fix I've confirmed that the previously-missed XSS paths are now detected.

asgerf avatar Nov 25 '25 15:11 asgerf