typescript.react.security.audit.react-href-var.react-href-var

profile photo of semgrepsemgrep
Author
5,893
Download Count*

Detected a variable used in an anchor tag with the 'href' attribute. A malicious actor may be able to input the 'javascript:' URI, which could cause cross-site scripting (XSS). It is recommended to disallow 'javascript:' URIs within your application.

Run Locally

Run in CI

Defintion

rules:
  - id: react-href-var
    message: Detected a variable used in an anchor tag with the 'href' attribute. A
      malicious actor may be able to input the 'javascript:' URI, which could
      cause cross-site scripting (XSS). It is recommended to disallow
      'javascript:' URIs within your application.
    metadata:
      cwe:
        - "CWE-79: Improper Neutralization of Input During Web Page Generation
          ('Cross-site Scripting')"
      owasp:
        - A07:2017 - Cross-Site Scripting (XSS)
        - A03:2021 - Injection
      references:
        - https://reactjs.org/blog/2019/08/08/react-v16.9.0.html#deprecating-javascript-urls
        - https://pragmaticwebsecurity.com/articles/spasecurity/react-xss-part1.html
      category: security
      confidence: LOW
      technology:
        - react
      license: Commons Clause License Condition v1.0[LGPL-2.1-only]
      cwe2022-top25: true
      cwe2021-top25: true
      subcategory:
        - audit
      likelihood: LOW
      impact: MEDIUM
      vulnerability_class:
        - Cross-Site-Scripting (XSS)
    languages:
      - typescript
      - javascript
    severity: WARNING
    mode: taint
    pattern-sources:
      - label: TAINTED
        patterns:
          - pattern-either:
              - pattern-inside: |
                  function ...({..., $X, ...}) { ... }
              - pattern-inside: |
                  function ...(..., $X, ...) { ... }
          - focus-metavariable: $X
          - pattern-either:
              - pattern: $X.$Y
              - pattern: $X[...]
          - pattern-not-inside: |
              $F. ... .$SANITIZEUNC(...)
      - label: CONCAT
        requires: TAINTED
        patterns:
          - pattern-either:
              - pattern: |
                  `...${$X}...`
              - pattern: |
                  $SANITIZE + <... $X ...>
          - pattern-not: |
              `${$X}...`
          - pattern-not: |
              $X + ...
          - focus-metavariable: $X
      - label: CLEAN
        by-side-effect: true
        patterns:
          - pattern-either:
              - pattern: $A($SOURCE)
              - pattern: $SANITIZE. ... .$A($SOURCE)
              - pattern: $A. ... .$SANITIZE($SOURCE)
          - focus-metavariable: $SOURCE
          - metavariable-regex:
              metavariable: $A
              regex: (?i)(.*valid|.*sanitiz)
    pattern-sinks:
      - requires: TAINTED and not CONCAT and not CLEAN
        patterns:
          - focus-metavariable: $X
          - pattern-either:
              - pattern: |
                  <$EL href={$X} />
              - pattern: |
                  React.createElement($EL, {href: $X})
              - pattern-inside: |
                  $PARAMS = {href: $X};
                  ...
                  React.createElement($EL, $PARAMS);
          - metavariable-pattern:
              patterns:
                - pattern-not-regex: (?i)(button)
              metavariable: $EL

Examples

react-href-var.jsx

import {
  SEMGREP_REPO,
} from "../../util";

import SEMGREP_REPO1 from "../../util1";

// ok: react-href-var
let zzz = <Foo className={"foobar"} href={getQuery()} />;

function test1(input) {
// ruleid: react-href-var
  const params = {href: input.a};
  return React.createElement("a", params);
}

// ok: react-href-var
{collaborationSectionData.paragraphs.map((item, i) => (
  <div>  <a href={item.value}>click</a></div>
))}

// ok: react-href-var
let zzz = <Foo className={"foobar"} href={`${input}`} />;

// ok: react-href-var
let zzz = <Foo className={"foobar"} href={SEMGREP_REPO} />;

// ok: react-href-var
let zzz = <Foo className={"foobar"} href={SEMGREP_REPO1} />;

function test1(input) {
// ok: react-href-var
  if(input.startsWith("https:")) {
    const params = {href: input};
    return React.createElement("a", params);
  }
}

function test2(input) {
  // ok: react-href-var
  const params = {href: "#"+input};
  return React.createElement("a", params);
}

function test2(input) {
  // ok: react-href-var
  const params = {href: "#"+input};
  return React.createElement("a", params);
}


// ok: react-href-var
const b = <a className={"foobar"} href={"http://www.example.com"}></a>;

// ok: react-href-var
let x = <a className={"foobar"} href={"#"+input}></a>;

// ok: react-href-var
let x = <a className={"foobar"} href={`#${input}`}></a>;

function okTest1() {
// ok: react-href-var
  return React.createElement("a", {href: "https://www.example.com"});
}

react-href-var.tsx

import {
  SEMGREP_REPO,
} from "../../util";

import SEMGREP_REPO1 from "../../util1";

// ok: react-href-var
let zzz = <Foo className={"foobar"} href={getQuery()} />;

function test1(input) {
// ruleid: react-href-var
  const params = {href: input.a};
  return React.createElement("a", params);
}

// ok: react-href-var
let zzz = <Foo className={"foobar"} href={`${input}`} />;

// ok: react-href-var
let zzz = <Foo className={"foobar"} href={SEMGREP_REPO} />;

// ok: react-href-var
let zzz = <Foo className={"foobar"} href={SEMGREP_REPO1} />;

function test1(input) {
// ok: react-href-var
  if(input.startsWith("https:")) {
    const params = {href: input};
    return React.createElement("a", params);
  }
}

function test2(input) {
  // ok: react-href-var
  const params = {href: "#"+input};
  return React.createElement("a", params);
}

function test2(input) {
  // ok: react-href-var
  const params = {href: "#"+input};
  return React.createElement("a", params);
}


// ok: react-href-var
const b = <a className={"foobar"} href={"http://www.example.com"}></a>;

// ok: react-href-var
let x = <a className={"foobar"} href={"#"+input}></a>;

// ok: react-href-var
let x = <a className={"foobar"} href={`#${input}`}></a>;

function okTest1() {
// ok: react-href-var
  return React.createElement("a", {href: "https://www.example.com"});
}