id: no-unsanitized-url-attr
language: tsx
severity: error
message: 'URL attribute fed from data must pass a safe-URL guard — a stored javascript:/data: URL executes on click'
note: '{"severity":"high","category":"security","resolution":"Wrap the value: href={safeHttpUrl(row.proof_url)}. The guard returns undefined for anything that is not http(s). NEVER interpolate a stored or API-supplied URL straight into href, src, action, or formAction."}'
files:
  - 'apps/web/src/**'
  - 'packages/deck-ui/src/**'
  - '**/.slopgate/fixtures/**'
ignores:
  - '**/*.test.tsx'
rule:
  all:
    - kind: jsx_attribute
    - regex: '^(href|src|action|formAction)=\{[A-Za-z_$][A-Za-z0-9_$]*\??\.'
    # Scope to real DOM sinks only: an intrinsic HTML element (lowercase tag,
    # e.g. <a>/<img>/<form>) navigates or submits on this attribute. A
    # capitalized JSX identifier is a React component prop — no browser sink
    # exists there regardless of the attribute's name.
    - inside:
        any:
          - kind: jsx_opening_element
          - kind: jsx_self_closing_element
        has:
          field: name
          regex: '^[a-z]'
