# OpenGrep super-config: precise
#
# Auto-generated by security/opengrep/compile-rules.mjs.
# DO NOT EDIT BY HAND. Re-run the compile script after editing source rules.
#
# Source rules dir: security/opengrep/rules/openclaw-policy
# Generated at    : 2026-04-30T09:09:41.198Z
# Rule count      : 148
rules:
  - id: ghsa-25gx-x37c-7pph.openclaw-novnc-x11vnc-missing-auth
    message: x11vnc starts without VNC authentication; avoid -nopw and require password auth when exposing noVNC observer access.
    severity: ERROR
    languages:
      - regex
    pattern-regex: x11vnc[^\n]*-nopw
    metadata:
      ghsa: GHSA-25GX-X37C-7PPH
      cwe: CWE-306
      category: security
      technology:
        - x11vnc
        - novnc
        - vnc
      confidence: high
      likelihood: medium
      impact: medium
      references:
        - https://github.com/openclaw/openclaw/security/advisories/GHSA-25gx-x37c-7pph
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-25GX-X37C-7PPH
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openclaw-novnc-x11vnc-missing-auth
  - id: ghsa-25pw-4h6w-qwvm.openclaw.imessage-group-allowlist-merged-with-pairing-store
    languages:
      - typescript
    severity: ERROR
    message: DM pairing-store identities are merged into a group allowlist. Group authorization must stay explicit and should not inherit DM pairing-store entries.
    patterns:
      - pattern: |
          const $STORE = await readChannelAllowFromStore(...).catch(() => []);
          ...
          const $GROUP = Array.from(new Set([...$GROUPALLOW, ...$STORE]))
            .map((v) => String(v).trim())
            .filter(Boolean);
    metadata:
      category: security
      cwe: CWE-863
      ghsa: GHSA-25PW-4H6W-QWVM
      confidence: high
      note: Captures the original iMessage vulnerable merge shape exactly and generalizes to same-family explicit merge sites.
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-25PW-4H6W-QWVM
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openclaw.imessage-group-allowlist-merged-with-pairing-store
  - id: ghsa-2prf-9cw7-fq62.whatsapp-reaction-requires-allowfrom-guard
    message: WhatsApp reaction actions should validate chatJid with resolveWhatsAppOutboundTarget before sendReactionWhatsApp.
    severity: ERROR
    languages:
      - typescript
    patterns:
      - pattern-inside: |
          if ($ACTION === "react") {
            ...
            await sendReactionWhatsApp($TARGET, $MSG, $EMOJI, ...)
            ...
          }
      - pattern: |
          await sendReactionWhatsApp($TARGET, $MSG, $EMOJI, ...)
      - metavariable-pattern:
          metavariable: $TARGET
          language: generic
          patterns:
            - pattern-not: $RES.to
      - pattern-not-inside: |
          $RES = resolveWhatsAppOutboundTarget({
            ...,
            to: $TARGET,
            ...
          });
          ...
          if (!$RES.ok) {
            ...
          }
          ...
          await sendReactionWhatsApp($RES.to, $MSG, $EMOJI, ...)
    metadata:
      category: security
      cwe:
        - CWE-862
        - CWE-20
      ghsa: GHSA-2PRF-9CW7-FQ62
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-2PRF-9CW7-FQ62
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: whatsapp-reaction-requires-allowfrom-guard
  - id: ghsa-2qj5-gwg2-xwc4.openclaw.prompt-unsanitized-literal-interpolation
    languages:
      - typescript
      - javascript
    severity: ERROR
    message: |
      Untrusted runtime path/URL value flows into a string literal inside a prompt-builder function, without going through sanitizeForPromptLiteral or wrapUntrustedPromptDataBlock. Workspace paths can contain Unicode control / format characters that break LLM prompt structure (CVE-2026-27001 / GHSA-2qj5-gwg2-xwc4).
    mode: taint
    pattern-sources:
      - patterns:
          - pattern-either:
              - pattern: $X.workspaceDir
              - pattern: $X.containerWorkspaceDir
              - pattern: $X.agentWorkspaceMount
              - pattern: $X.browserNoVncUrl
              - pattern: $X.displayWorkspaceDir
              - pattern: $X.mountPath
              - pattern: $X.canvasRootDir
              - pattern: $X.cwd
    pattern-sanitizers:
      - patterns:
          - pattern-either:
              - pattern: sanitizeForPromptLiteral(...)
              - pattern: sanitizeForPromptLiterals(...)
              - pattern: wrapUntrustedPromptDataBlock(...)
              - patterns:
                  - pattern: $F(...)
                  - metavariable-regex:
                      metavariable: $F
                      regex: ^(sanitize|escape|validate)[A-Z]\w*Prompt\w*$
    pattern-sinks:
      - patterns:
          - pattern-either:
              - pattern: |
                  `...${$VALUE}...`
              - pattern: |
                  "..." + $VALUE + "..."
              - pattern: |
                  '...' + $VALUE + '...'
          - pattern-either:
              - pattern-inside: |
                  function $FN(...) { ... }
              - pattern-inside: |
                  const $FN = (...) => { ... }
              - pattern-inside: |
                  export function $FN(...) { ... }
              - pattern-inside: |
                  export const $FN = (...) => { ... }
          - metavariable-regex:
              metavariable: $FN
              regex: ^(build|render|compose|construct|format)[A-Z]\w*Prompt\w*$
    metadata:
      ghsa: GHSA-2QJ5-GWG2-XWC4
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-2QJ5-GWG2-XWC4
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openclaw.prompt-unsanitized-literal-interpolation
  - id: ghsa-2qrv-rc5x-2g2h.openclaw-untrusted-workspace-channel-shadow-setup
    languages:
      - typescript
      - javascript
    severity: ERROR
    mode: taint
    message: Workspace-aware channel-plugin catalog lookup at channel-setup time reaches a use site without going through resolveTrustedCatalogEntry() or excludeWorkspace:true. Workspace-defined channel shadows could execute during built-in channel setup. See GHSA-2QRV-RC5X-2G2H.
    metadata:
      category: security
      ghsas:
        - GHSA-2QRV-RC5X-2G2H
      ghsa: GHSA-2QRV-RC5X-2G2H
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-2QRV-RC5X-2G2H
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openclaw-untrusted-workspace-channel-shadow-setup
    paths:
      include:
        - src/commands/channel-setup/*.ts
        - src/flows/channel-setup.ts
        - src/commands/channels/add.ts
      exclude:
        - "**/*.test.*"
        - "**/*.spec.*"
        - src/commands/channel-setup/trusted-catalog.ts
    pattern-sources:
      - patterns:
          - pattern-either:
              - pattern: getChannelPluginCatalogEntry(...)
              - pattern: listChannelPluginCatalogEntries(...)
          - pattern-not-regex: \bexcludeWorkspace\s*:\s*true\b
    pattern-sanitizers:
      - patterns:
          - pattern-either:
              - pattern: resolveTrustedCatalogEntry(...)
              - pattern: listTrustedChannelPluginCatalogEntries(...)
              - pattern: listSetupDiscoveryChannelPluginCatalogEntries(...)
    pattern-sinks:
      - patterns:
          - pattern-either:
              - pattern: $X.filter(...)
              - pattern: $X.map(...)
              - pattern: $X.flatMap(...)
              - pattern: $X.find(...)
              - pattern: $X.forEach(...)
              - pattern: $X.some(...)
              - pattern: $X.every(...)
              - pattern: $X.id
              - pattern: $X.meta
              - pattern: $X.plugin
              - pattern: $X[$I]
              - pattern: return $X;
              - pattern: new Map($X)
              - pattern: new Set($X)
  - id: ghsa-2rgf-hm63-5qph.xff-last-hop-without-trusted-proxy-context
    languages:
      - typescript
      - javascript
    severity: WARNING
    message: Review X-Forwarded-For parsers that pick the last header hop directly instead of walking past trusted proxies.
    metadata:
      category: security
      cwe:
        - CWE-345
        - CWE-807
      ghsa: GHSA-2RGF-HM63-5QPH
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-2RGF-HM63-5QPH
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: xff-last-hop-without-trusted-proxy-context
    pattern-either:
      - patterns:
          - pattern: |
              const $ENTRIES = $FORWARDED
                ?.split(",")
                .map(($ENTRY) => $MAP)
                .filter(($FILTER) => $PRED);
              const $RAW = $ENTRIES?.at(-1);
              ...
              return $NORMALIZE($STRIP($RAW));
      - patterns:
          - pattern: |
              const $HOPS = $FORWARDED
                ?.split(",")
                .map(($ENTRY) => $MAP)
                .filter(($FILTER) => $PRED);
              ...
              return $SANITIZE($HOPS[$HOPS.length - 1]);
  - id: ghsa-2x4x-cc5g-qmmg.node-pair-approve-missing-callerscopes-object
    languages:
      - typescript
      - javascript
    severity: ERROR
    message: approveNodePairing on node approval paths should receive an options object that carries callerScopes.
    patterns:
      - pattern-either:
          - pattern: approveNodePairing($REQ)
          - pattern: approveNodePairing($REQ, undefined, ...)
    metadata:
      ghsa: GHSA-2X4X-CC5G-QMMG
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-2X4X-CC5G-QMMG
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: node-pair-approve-missing-callerscopes-object
  - id: ghsa-3298-56p6-rpw2.openclaw-killprocesstree-from-shell-utils
    languages:
      - typescript
    severity: ERROR
    message: killProcessTree from agents/shell-utils performs an immediate ungraceful SIGKILL on the entire process tree. Use the killProcessTree from src/process/kill-tree.ts (which sends SIGTERM, waits graceMs, then SIGKILL only if needed). See GHSA-3298-56P6-RPW2.
    metadata:
      category: security
      cwe:
        - CWE-697
      ghsas:
        - GHSA-3298-56P6-RPW2
      ghsa: GHSA-3298-56P6-RPW2
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-3298-56P6-RPW2
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openclaw-killprocesstree-from-shell-utils
    paths:
      exclude:
        - "**/*.test.*"
        - "**/*.spec.*"
        - src/process/kill-tree.ts
    pattern-either:
      - pattern: import { ..., killProcessTree, ... } from "../shell-utils"
      - pattern: import { ..., killProcessTree, ... } from "./shell-utils"
      - pattern: import { ..., killProcessTree, ... } from "../agents/shell-utils"
      - pattern: import { ..., killProcessTree, ... } from "src/agents/shell-utils"
      - pattern: import { ..., killProcessTree, ... } from "../../agents/shell-utils"
      - pattern: |
          export function killProcessTree($PID: number): void { ... process.kill($X, "SIGKILL"); ... }
  - id: ghsa-33hm-cq8r-wc49.openclaw-sandbox-tmp-accepts-os-tmpdir
    languages:
      - typescript
      - javascript
    message: Sandbox tmp-path validation trusts any os.tmpdir() path instead of constraining paths to the active sandbox root or OpenClaw-managed temp roots.
    severity: ERROR
    patterns:
      - pattern-either:
          - pattern: |
              const $TMP = path.resolve(os.tmpdir())
              ...
              if (!isPathInside($TMP, $RESOLVED)) {
                return undefined;
              }
              ...
              return $RESOLVED;
          - pattern: |
              const $TMP = path.resolve(os.tmpdir())
              ...
              if (!isPathInside($TMP, $ABS)) {
                return undefined;
              }
              ...
              return $ABS;
    metadata:
      category: security
      cwe:
        - CWE-22
        - CWE-284
      ghsa: GHSA-33HM-CQ8R-WC49
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-33HM-CQ8R-WC49
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openclaw-sandbox-tmp-accepts-os-tmpdir
  - id: ghsa-354r-7mfh-7rh2.review-reaction-enqueue-without-dm-access-check
    languages:
      - typescript
      - javascript
    severity: WARNING
    message: Reaction handlers that enqueue system events without calling resolveDmGroupAccessWithLists need review for DM authorization parity.
    paths:
      include:
        - src/discord/monitor/listeners.ts
        - src/slack/monitor/events/reactions.ts
    patterns:
      - pattern-either:
          - pattern: |
              async function $F(...){
                ...
                enqueueSystemEvent($TEXT, $OPTS)
                ...
              }
          - pattern: |
              const $F = async (...) => {
                ...
                enqueueSystemEvent($TEXT, $OPTS)
                ...
              }
      - pattern-regex: reaction|Reaction|messageReaction|reaction_added|reaction_removed
      - pattern-not-regex: resolveDmGroupAccessWithLists
    metadata:
      ghsa: GHSA-354R-7MFH-7RH2
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-354R-7MFH-7RH2
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: review-reaction-enqueue-without-dm-access-check
  - id: ghsa-36h3-7c54-j27r.browser-route-tempdir-write-missing-symlink-guard
    message: Browser route handler writes to a path under the managed temp root without going through resolveWritablePathWithinRoot. The gate is needed to refuse symlink-root and symlink-parent escapes from the temp dir (otherwise an attacker can place a symlink at any directory component and escape the boundary). See GHSA-36H3-7C54-J27R.
    severity: ERROR
    languages:
      - typescript
    metadata:
      ghsa: GHSA-36H3-7C54-J27R
      category: security
      cwe:
        - CWE-22
        - CWE-59
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-36H3-7C54-J27R
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: browser-route-tempdir-write-missing-symlink-guard
    paths:
      include:
        - extensions/browser/src/browser/routes/output-paths.ts
        - extensions/browser/src/browser/routes/agent.act*.ts
        - extensions/browser/src/browser/routes/agent.debug*.ts
    patterns:
      - pattern-either:
          - pattern: fs.mkdir(...)
          - pattern: fs.mkdirSync(...)
          - pattern: fsp.mkdir(...)
          - pattern: fs.createWriteStream(...)
          - pattern: fs.writeFile(...)
          - pattern: fsp.writeFile(...)
      - pattern-not-inside: |
          import { ..., resolveWritablePathWithinRoot, ... } from "$X";
          ...
      - pattern-not-inside: |
          import { resolveWritablePathWithinRoot } from "$X";
          ...
      - pattern-not-inside: |
          import { resolveWritablePathWithinRoot, ... } from "$X";
          ...
  - id: ghsa-39mp-545q-w789.openclaw-owner-only-send-policy-mutation
    message: Owner-only /send handlers must reject non-owner senders before mutating sessionEntry.sendPolicy.
    severity: ERROR
    languages:
      - typescript
      - javascript
    patterns:
      - pattern-inside: |
          const $PARSED = parseSendPolicyCommand($CMD);
          ...
      - pattern: |
          if (!$PARAMS.command.isAuthorizedSender) {
            ...
            return ...;
          }
          ...
          if ($PARAMS.sessionEntry && $PARAMS.sessionStore && $PARAMS.sessionKey) {
            ...
            $MUTATION
            ...
          }
      - metavariable-pattern:
          metavariable: $MUTATION
          patterns:
            - pattern-either:
                - pattern: $PARAMS.sessionEntry.sendPolicy = $MODE;
                - pattern: delete $PARAMS.sessionEntry.sendPolicy;
      - pattern-not-inside: |
          const $NONOWNER = rejectNonOwnerCommand($PARAMS, "/send");
          if ($NONOWNER) {
            return $NONOWNER;
          }
      - pattern-not-inside: |
          if (!$PARAMS.command.senderIsOwner) {
            ...
            return ...;
          }
    metadata:
      ghsa: GHSA-39MP-545Q-W789
      category: authorization
      detector: A
      coverage_requirement: vulnerable_fix_diff_files
      review_surface: owner_only_send_policy
      rationale: catches /send policy mutations guarded only by general authorization
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-39MP-545Q-W789
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openclaw-owner-only-send-policy-mutation
  - id: ghsa-3cw3-5vxw-g2h3.discovery-txt-hint-routing
    languages:
      - swift
    severity: ERROR
    message: Discovery helpers should not fall back to TXT-derived lanHost or tailnetDns values when building SSH targets or direct gateway URLs. Use resolved service endpoints only.
    patterns:
      - pattern-either:
          - pattern: let host = self.sanitizedTailnetHost($GW.tailnetDns) ?? $GW.lanHost
          - pattern: let host = sanitizeTailnet($GW.tailnetDns) ?? $GW.lanHost
          - pattern: guard let lanHost = self.trimmed(lanHost), !lanHost.isEmpty else { return nil }
          - pattern: let port = gatewayPort ?? 18789
    metadata:
      ghsa: GHSA-3CW3-5VXW-G2H3
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-3CW3-5VXW-G2H3
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: discovery-txt-hint-routing
  - id: ghsa-3hcm-ggvf-rch5.exec-allowlist-double-quoted-command-substitution
    languages:
      - typescript
      - javascript
    severity: ERROR
    message: Shell allowlist parsers that stay in double-quote mode without rejecting command substitution or backticks can approve commands that execute hidden substitutions.
    patterns:
      - pattern-either:
          - patterns:
              - pattern-inside: |
                  if ($IN_DOUBLE) {
                    ...
                  }
              - pattern: |
                  if ($CH === "\"") {
                    $IN_DOUBLE = false;
                  }
                  ...
                  $BUF += $CH;
              - pattern-not: |
                  if ($CH === "$" && $NEXT === "(") {
                    ...
                  }
              - pattern-not: |
                  if ($CH === "`") {
                    ...
                  }
          - patterns:
              - pattern-inside: |
                  if ($IN_DOUBLE) {
                    ...
                  }
              - pattern: |
                  if ($CH === "\"") {
                    $IN_DOUBLE = false;
                  } else {
                    $BUF += $CH;
                  }
              - pattern-not: |
                  if ($CH === "$" && $NEXT === "(") {
                    ...
                  }
              - pattern-not: |
                  if ($CH === "`") {
                    ...
                  }
    metadata:
      ghsa: GHSA-3HCM-GGVF-RCH5
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-3HCM-GGVF-RCH5
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: exec-allowlist-double-quoted-command-substitution
  - id: ghsa-3q42-xmxv-9vfr.openclaw-talk-voice-set-without-admin-scope-check
    message: Command handlers that persist talk voice config via writeConfigFile should reject gateway-scoped callers lacking operator.admin before writing the config.
    severity: ERROR
    languages:
      - typescript
    metadata:
      ghsa: GHSA-3Q42-XMXV-9VFR
      cwe: CWE-269
      detector: A
      confidence: low
      category: security
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-3Q42-XMXV-9VFR
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openclaw-talk-voice-set-without-admin-scope-check
    patterns:
      - pattern: |
          if ($ACTION === "set") {
            ...
            await $RUNTIME.config.writeConfigFile($NEXT)
            ...
          }
      - pattern-not: |
          if ($ACTION === "set") {
            ...
            if (requiresAdminToSetVoice($CTX.channel, $CTX.gatewayClientScopes)) {
              return ...;
            }
            ...
            await $RUNTIME.config.writeConfigFile($NEXT)
            ...
          }
      - pattern-not: |
          if ($ACTION === "set") {
            ...
            if (! $CTX.gatewayClientScopes?.includes("operator.admin")) {
              return ...;
            }
            ...
            await $RUNTIME.config.writeConfigFile($NEXT)
            ...
          }
  - id: ghsa-4685-c5cp-vp95.safe-bin-missing-blocked-option-policy
    languages:
      - typescript
      - javascript
    message: Safe-bin usage validators should reject dangerous sort/grep flags with hasBlockedSafeBinOption before accepting option tokens.
    severity: ERROR
    patterns:
      - pattern-inside: |
          function isSafeBinUsage(...) {
            ...
          }
      - pattern: |
          if ($TOKEN.startsWith("-")) {
            ...
          }
      - pattern-not-inside: |
          if ($TOKEN.startsWith("-")) {
            if (hasBlockedSafeBinOption($EXEC, $TOKEN)) {
              ...
            }
            ...
          }
    metadata:
      ghsa: GHSA-4685-C5CP-VP95
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-4685-C5CP-VP95
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: safe-bin-missing-blocked-option-policy
  - id: ghsa-49cg-279w-m73x.approval-auth-empty-approver-authorized
    languages:
      - typescript
    severity: ERROR
    message: Empty approver lists should stay implicit same-chat fallback; do not return explicit authorized approval auth when approvers.length === 0.
    patterns:
      - pattern-inside: |
          if ($APPROVERS.length === 0) {
            ...
          }
      - pattern-either:
          - pattern: |
              return { authorized: true } as const;
          - pattern: |
              return { authorized: true };
    metadata:
      category: security
      confidence: medium
      technology:
        - typescript
      ghsa: GHSA-49CG-279W-M73X
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-49CG-279W-M73X
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: approval-auth-empty-approver-authorized
  - id: ghsa-4cqv-h74h-93j4.discord-allowlist-name-matching-without-dangerous-opt-in
    message: Discord allowlist matching uses mutable names/tags without an explicit dangerous opt-in.
    languages:
      - typescript
      - javascript
    severity: ERROR
    patterns:
      - pattern-either:
          - pattern: |
              allowListMatches($LIST, $CANDIDATE)
          - pattern: |
              resolveDiscordAllowListMatch({
                allowList: $LIST,
                candidate: $CANDIDATE,
                ...,
              })
          - pattern: |
              resolveDiscordAllowListMatch({
                ...,
                allowList: $LIST,
                candidate: $CANDIDATE,
              })
      - pattern-not: |
          allowListMatches($LIST, $CANDIDATE, { allowNameMatching: ... })
      - pattern-not: |
          resolveDiscordAllowListMatch({
            allowList: $LIST,
            candidate: $CANDIDATE,
            allowNameMatching: ...,
            ...,
          })
      - pattern-not: |
          resolveDiscordAllowListMatch({
            ...,
            allowList: $LIST,
            candidate: $CANDIDATE,
            allowNameMatching: ...,
          })
    metadata:
      family: discord-allowlist-name-matching
      review: reusable structural rule for missing dangerous opt-in
      ghsa: GHSA-4CQV-H74H-93J4
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-4CQV-H74H-93J4
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: discord-allowlist-name-matching-without-dangerous-opt-in
  - id: ghsa-4g5x-2jfc-xm98.raw-fetch-to-disk-bypasses-media-runtime
    message: Remote media downloads should use the shared bounded media-runtime helpers instead of fetchWithSsrFGuard plus direct response-body-to-disk writes, which bypass core size, cleanup, and inbound-store limits.
    severity: ERROR
    languages:
      - typescript
      - javascript
    patterns:
      - pattern-inside: |
          async function $F(...){
            ...
          }
      - pattern: |
          const { response, release } = await fetchWithSsrFGuard({ ... });
          ...
          await pipeline(Readable.fromWeb($BODY), $WRITESTREAM);
          ...
      - pattern-not-inside: |
          const $FETCHED = await fetchRemoteMedia({ ... });
          ...
      - pattern-not-inside: |
          await saveMediaBuffer(...)
    metadata:
      category: security
      confidence: medium
      ghsa: GHSA-4G5X-2JFC-XM98
      detector: A
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-4G5X-2JFC-XM98
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: raw-fetch-to-disk-bypasses-media-runtime
  - id: ghsa-4rj2-gpmh-qq5x.inbound-allowlist-bidirectional-endswith
    languages:
      - typescript
      - javascript
    severity: ERROR
    message: Bidirectional endsWith on normalized caller and allowlist values can bypass inbound allowlists. Reject empty caller IDs and compare canonicalized identifiers with strict equality.
    patterns:
      - pattern-either:
          - pattern: |
              $FROM.endsWith($ALLOW) || $ALLOW.endsWith($FROM)
          - pattern: |
              $ALLOW.endsWith($FROM) || $FROM.endsWith($ALLOW)
    metavariable-comparison:
      metavariable: $FROM
      comparison: str($FROM) != str($ALLOW)
    metadata:
      category: security
      confidence: high
      cwe: CWE-287
      ghsa: GHSA-4RJ2-GPMH-QQ5X
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-4RJ2-GPMH-QQ5X
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: inbound-allowlist-bidirectional-endswith
  - id: ghsa-527m-976r-jf79.browser-existing-session-interaction-missing-navigation-guard
    message: Existing-session browser interaction routes must call assertExistingSessionPostInteractionNavigationAllowed (or use withBrowserNavigationPolicy) to apply the SSRF navigation guard. Without this gate, click/keyboard/script interactions can navigate to internal IPs / cloud metadata endpoints that the operator hasn't allowed. See GHSA-527M-976R-JF79.
    severity: ERROR
    languages:
      - typescript
    metadata:
      ghsa: GHSA-527M-976R-JF79
      category: security
      cwe:
        - CWE-918
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-527M-976R-JF79
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: browser-existing-session-interaction-missing-navigation-guard
    paths:
      include:
        - extensions/browser/src/browser/routes/agent.act*.ts
      exclude:
        - extensions/browser/src/browser/routes/agent.act.hooks.ts
    patterns:
      - pattern-either:
          - pattern: evaluateChromeMcpScript(...)
          - pattern: clickChromeMcpElement(...)
          - pattern: typeChromeMcpKeys(...)
      - pattern-not-inside: |
          import { ..., assertExistingSessionPostInteractionNavigationAllowed, ... } from "$X";
          ...
      - pattern-not-inside: |
          import { ..., assertBrowserNavigationResultAllowed, ... } from "$X";
          ...
      - pattern-not-inside: |
          import { assertBrowserNavigationResultAllowed } from "$X";
          ...
  - id: ghsa-536q-mj95-h29h.openclaw-browser-interaction-navigation-guard
    languages:
      - typescript
    severity: ERROR
    message: Browser interaction helpers that expose opts.ssrfPolicy and perform press-based actions should route the action through assertInteractionNavigationCompletedSafely so delayed post-action navigations still receive SSRF enforcement.
    patterns:
      - pattern-either:
          - pattern: |
              export async function $FN(opts: $OPTS) {
                ...
                await $PAGE.keyboard.press(...);
                ...
              }
          - pattern: |
              export async function $FN(opts: $OPTS) {
                ...
                await $LOCATOR.press(...);
                ...
              }
      - pattern: opts.ssrfPolicy
      - pattern-not-inside: |
          export async function $FN(opts: $OPTS) {
            ...
            await assertInteractionNavigationCompletedSafely({
              ...
            });
            ...
          }
      - pattern-not-inside: |
          export async function $FN(opts: $OPTS) {
            ...
            return await assertInteractionNavigationCompletedSafely({
              ...
            });
            ...
          }
    metadata:
      category: security
      confidence: medium
      technology:
        - playwright
        - browser
      ghsa: GHSA-536Q-MJ95-H29H
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-536Q-MJ95-H29H
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openclaw-browser-interaction-navigation-guard
  - id: ghsa-56f2-hvwg-5743.openclaw-unguarded-remote-media-fetch
    message: Remote media fetch should go through the SSRF guard instead of calling fetch directly.
    severity: ERROR
    languages:
      - typescript
    patterns:
      - pattern-either:
          - pattern: |
              export async function fetchRemoteMedia(...) {
                ...
                $RES = await $FETCHER($URL, ...);
                ...
              }
          - pattern: |
              async function fetchRemoteMedia(...) {
                ...
                $RES = await $FETCHER($URL, ...);
                ...
              }
      - metavariable-regex:
          metavariable: $URL
          regex: (^url$|^requestUrl$|^mediaUrl$)
    metadata:
      cwe: CWE-918
      ghsa: GHSA-56F2-HVWG-5743
      detector: A
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-56F2-HVWG-5743
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openclaw-unguarded-remote-media-fetch
  - id: ghsa-5mx2-2mgw-x8rm.openclaw-webhook-loopback-passwordless-fallback
    languages:
      - typescript
    severity: ERROR
    message: Webhook auth falls back to passwordless targets on loopback instead of requiring configured secret matching.
    pattern: |
      const $MATCHING =
        $STRICT.length > 0
          ? $STRICT
          : isDirectLocalLoopbackRequest($REQ)
            ? $PASSWORDLESS
            : [];
    metadata:
      ghsa: GHSA-5MX2-2MGW-X8RM
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-5MX2-2MGW-X8RM
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openclaw-webhook-loopback-passwordless-fallback
  - id: ghsa-5v6x-rfc3-7qfr.openclaw-system-run-approval-legacy-command-only-binding
    message: system.run approval matching should bind to exact argv/canonical command data, not legacy command-only text.
    languages:
      - typescript
      - javascript
    severity: ERROR
    patterns:
      - pattern-inside: |
          function $F(...){
            ...
          }
      - pattern: |
          if (!$REQ.systemRunBinding) {
            return $MISMATCH(...);
          }
      - pattern: |
          return $MATCH({
            expected: $REQ.systemRunBinding,
            actual: $ACTUAL.binding,
            actualEnvKeys: $ACTUAL.envKeys,
          });
    metadata:
      confidence: medium
      ghsa: GHSA-5V6X-RFC3-7QFR
      detector: A
      rationale: Requires v1 structured approval binding before matching.
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-5V6X-RFC3-7QFR
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openclaw-system-run-approval-legacy-command-only-binding
  - id: ghsa-5wcw-8jjv-m286.trusted-proxy-accept-without-origin-guard
    languages:
      - typescript
      - javascript
    message: Trusted-proxy authorization returns success without first applying authorizeTrustedProxyBrowserOrigin.
    severity: ERROR
    patterns:
      - pattern: |
          if ("user" in $RESULT) {
            ...
            return { ok: true, method: "trusted-proxy", user: $RESULT.user };
          }
      - pattern-not: |
          if ("user" in $RESULT) {
            ...
            const $ORIGIN_RESULT = authorizeTrustedProxyBrowserOrigin(...);
            ...
            if ($ORIGIN_RESULT) {
              ...
            }
            ...
            return { ok: true, method: "trusted-proxy", user: $RESULT.user };
          }
    metadata:
      category: security
      confidence: medium
      ghsa: GHSA-5WCW-8JJV-M286
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-5WCW-8JJV-M286
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: trusted-proxy-accept-without-origin-guard
  - id: ghsa-5xfq-5mr7-426q.openclaw-session-transcript-path-traversal
    message: Transcript path helper uses unvalidated sessionId or returns raw sessionFile without containment enforcement.
    severity: WARNING
    languages:
      - typescript
    pattern-either:
      - pattern: "return candidate ? candidate : resolveSessionTranscriptPath(sessionId, opts?.agentId)"
      - pattern: return path.join(resolveAgentSessionsDir(agentId), fileName)
    metadata:
      category: security
      cwe:
        - CWE-22
      ghsa: GHSA-5XFQ-5MR7-426Q
      confidence: low
      justification: Coverage-first detector for the vulnerable family in pre-fix session transcript path helpers.
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-5XFQ-5MR7-426Q
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openclaw-session-transcript-path-traversal
  - id: ghsa-62f6-mrcj-v8h5.runtime-overrides-unsanitized-override-store
    languages:
      - typescript
      - javascript
    severity: WARNING
    message: Runtime override stores should sanitize object values before set-at-path writes to block prototype-reserved keys.
    patterns:
      - pattern-inside: |
          function $F(..., $VALUE, ...) {
            ...
          }
      - pattern: setConfigValueAtPath($TREE, $PATH, $VALUE)
      - pattern-not: setConfigValueAtPath($TREE, $PATH, sanitizeOverrideValue($VALUE))
      - pattern-not: setConfigValueAtPath($TREE, $PATH, sanitizeInput($VALUE))
      - metavariable-regex:
          metavariable: $F
          regex: ^set.*Override$
    metadata:
      ghsa: GHSA-62F6-MRCJ-V8H5
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-62F6-MRCJ-V8H5
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: runtime-overrides-unsanitized-override-store
  - id: ghsa-65rx-fvh6-r4h2.openclaw-unquoted-heredoc-body-missing-expansion-token-guard
    languages:
      - typescript
    severity: ERROR
    message: Heredoc body parsing resets heredocLine after delimiter matching without checking hasUnquotedHeredocExpansionToken() for unquoted heredocs. Shell command substitution in heredoc bodies can bypass exec allowlist analysis. See GHSA-65RX-FVH6-R4H2.
    metadata:
      ghsa: GHSA-65RX-FVH6-R4H2
      category: security
      cwe:
        - CWE-78
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-65RX-FVH6-R4H2
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openclaw-unquoted-heredoc-body-missing-expansion-token-guard
    paths:
      include:
        - src/infra/exec-approvals-analysis.ts
    patterns:
      - pattern: |
          if (current) {
            const line = current.stripTabs ? heredocLine.replace(/^\t+/, "") : heredocLine;
            if (line === current.delimiter) {
              pendingHeredocs.shift();
            }
          }
          heredocLine = "";
      - pattern-not: |
          if (current) {
            const line = current.stripTabs ? heredocLine.replace(/^\t+/, "") : heredocLine;
            if (line === current.delimiter) {
              pendingHeredocs.shift();
            } else if (!current.quoted && hasUnquotedHeredocExpansionToken(heredocLine)) {
              return { ok: false, reason: "command substitution in unquoted heredoc", segments: [] };
            }
          }
          heredocLine = "";
  - id: ghsa-66r7-m7xm-v49h.qqbot-outbound-media-unvalidated-local-path
    languages:
      - typescript
      - javascript
    severity: ERROR
    message: QQBot outbound helper resolves local media paths without media-root boundary validation.
    patterns:
      - pattern-either:
          - pattern: |
              const $MEDIA = resolveQQBotLocalMediaPath(normalizePath(...));
          - pattern: |
              const $MEDIA = resolveQQBotLocalMediaPath($PATH);
      - pattern-inside: |
          export async function $FN(...){
            ...
          }
      - metavariable-regex:
          metavariable: $FN
          regex: ^(sendPhoto|sendVoice|sendVideoMsg|sendDocument|sendMedia|sendVoiceMessage)$
      - pattern-not-inside: |
          const $RESOLVED = resolveOutboundMediaPath(...);
          ...
    metadata:
      ghsa: GHSA-66R7-M7XM-V49H
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-66R7-M7XM-V49H
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: qqbot-outbound-media-unvalidated-local-path
  - id: ghsa-6g25-pc82-vfwp.oauth-state-reuses-pkce-verifier
    languages:
      - typescript
      - javascript
    message: OAuth state should be generated independently, not reused from the PKCE verifier/codeVerifier.
    severity: WARNING
    patterns:
      - pattern-either:
          - pattern: |
              function $F(..., $VERIFIER, ...) {
                ...
                new URLSearchParams({ ..., state: $VERIFIER, ... })
                ...
              }
          - pattern: |
              function $F(..., $VERIFIER, ...) {
                ...
                const $P = new URLSearchParams(...);
                ...
                $P.set('state', $VERIFIER)
                ...
              }
      - metavariable-regex:
          metavariable: $VERIFIER
          regex: (?i).*(verifier|codeVerifier).*
    metadata:
      ghsa: GHSA-6G25-PC82-VFWP
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-6G25-PC82-VFWP
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: oauth-state-reuses-pkce-verifier
  - id: ghsa-6mqc-jqh6-x8fc.openclaw-canvas-auth-local-direct-bypass
    message: Canvas/A2UI auth helper allows local-direct requests before bearer-or-capability auth.
    severity: ERROR
    languages:
      - typescript
      - javascript
    patterns:
      - pattern-inside: |
          async function $F(...){
            ...
          }
      - pattern-either:
          - pattern: |
              if (isLocalDirectRequest($REQ, ...)) {
                return { ok: true };
              }
          - pattern: |
              const $LOCAL = isLocalDirectRequest($REQ, ...);
              ...
              if ($LOCAL) {
                return { ok: true };
              }
    metavariable-regex:
      metavariable: $F
      regex: authorize.*
    metadata:
      ghsa: GHSA-6MQC-JQH6-X8FC
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-6MQC-JQH6-X8FC
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openclaw-canvas-auth-local-direct-bypass
  - id: ghsa-767m-xrhc-fxm7.telegram-target-writeback-admin-scope-required
    message: Calls to maybePersistResolvedTelegramTarget should propagate gatewayClientScopes so the helper can enforce operator.admin before persisting Telegram target rewrites.
    severity: ERROR
    languages:
      - typescript
    patterns:
      - pattern: |
          maybePersistResolvedTelegramTarget({
            ...,
            rawTarget: $RAW,
            ...,
            resolvedChatId: $CHAT,
            ...,
          })
      - pattern-not: |
          maybePersistResolvedTelegramTarget({
            ...,
            gatewayClientScopes: $SCOPES,
            ...,
          })
    metadata:
      ghsa: GHSA-767M-XRHC-FXM7
      detector: A
      rationale: Structural callsite check for helper invocations that omit gatewayClientScopes, which disables the operator.admin gate inside Telegram target writeback persistence.
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-767M-XRHC-FXM7
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: telegram-target-writeback-admin-scope-required
  - id: ghsa-77w2-crqv-cmv3.feishu-structured-card-action-envelope-required
    languages:
      - typescript
      - javascript
    severity: ERROR
    message: Feishu interactive card buttons that trigger commands or text should use a structured interaction envelope instead of raw text/command callback values.
    patterns:
      - pattern-either:
          - pattern: |
              {
                ...,
                tag: "button",
                ...,
                value: { command: $CMD, ... },
                ...,
              }
          - pattern: |
              {
                ...,
                tag: "button",
                ...,
                value: { text: $TXT, ... },
                ...,
              }
    paths:
      include:
        - "**/*.ts"
        - "**/*.js"
    metadata:
      ghsa: GHSA-77W2-CRQV-CMV3
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-77W2-CRQV-CMV3
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: feishu-structured-card-action-envelope-required
  - id: ghsa-782p-5fr5-7fj8.channel-metadata-into-trusted-system-prompt
    languages:
      - typescript
    severity: WARNING
    message: Untrusted channel metadata is being interpolated into trusted GroupSystemPrompt parts. Route it through UntrustedContext instead.
    pattern-either:
      - pattern: |
          const $SYSTEM_PROMPT_PARTS = [
            ...,
            $CHANNEL_DESC ? `Channel description: ${$CHANNEL_DESC}` : null,
            ...,
          ].filter(($ENTRY) => Boolean($ENTRY));
      - pattern: |
          const $SYSTEM_PROMPT_PARTS = [
            ...,
            $CHANNEL_DESC ? `Channel topic: ${$CHANNEL_DESC}` : null,
            ...,
          ].filter(($ENTRY) => Boolean($ENTRY));
      - pattern: |
          const $SYSTEM_PROMPT_PARTS = [
            ...,
            $CHANNEL_DESC ? `Forum topic: ${$CHANNEL_DESC}` : null,
            ...,
          ].filter(($ENTRY) => Boolean($ENTRY));
    metadata:
      ghsa: GHSA-782P-5FR5-7FJ8
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-782P-5FR5-7FJ8
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: channel-metadata-into-trusted-system-prompt
  - id: ghsa-796m-2973-wc5q.env-wrapper-transparent-unwrap
    languages:
      - typescript
      - javascript
    severity: WARNING
    message: env dispatch-wrapper handling unwraps env invocations without a semantic-modifier guard. Review whether env assignments or env -S/--split-string can change runtime behavior and bypass policy expectations.
    patterns:
      - pattern-either:
          - pattern: |
              case "env":
                return unwrapDispatchWrapper($WRAPPER, unwrapEnvInvocation($ARGV));
          - pattern: |
              if ($WRAP == "env") {
                return unwrapEnvInvocation($ARGV);
              }
    metadata:
      ghsa: GHSA-796M-2973-WC5Q
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-796M-2973-WC5Q
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: env-wrapper-transparent-unwrap
  - id: ghsa-7fcc-cw49-xm78.windows-shell-fallback-after-spawn-error
    message: Windows spawn retry logic that reruns the same operation with shell=true after ENOENT/EINVAL wrapper failures can turn argv into shell-interpreted command text.
    severity: ERROR
    languages:
      - typescript
      - javascript
    patterns:
      - pattern-either:
          - pattern: |
              if (process.platform === "win32" && ($ERR.code === "EINVAL" || $ERR.code === "ENOENT")) {
                ...
                return await $RUN(..., true);
              }
          - pattern: |
              if (process.platform === "win32" && ($ERR.code === "ENOENT" || $ERR.code === "EINVAL")) {
                ...
                return await $RUN(..., true);
              }
          - pattern: |
              if (process.platform === "win32" && $CHECK($ERR)) {
                ...
                return await $RUN(..., true);
              }
          - pattern: |
              if (process.platform === "win32" && $RETRYABLE) {
                ...
                return await $RUN(..., true);
              }
          - pattern: |
              if (process.platform === "win32") {
                ...
                if ($CHECK($ERR)) {
                  ...
                  return await $RUN(..., true);
                }
              }
      - pattern-either:
          - pattern-inside: |
              function $CHECK($ERR) {
                ...
                return $CODE === "EINVAL" || $CODE === "ENOENT";
              }
              ...
          - pattern-inside: |
              function $CHECK($ERR) {
                ...
                return $CODE === "ENOENT" || $CODE === "EINVAL";
              }
              ...
          - pattern-inside: |
              const $RETRYABLE = $ERR && ($ERR.code === "ENOENT" || $ERR.code === "EINVAL");
              ...
          - pattern-inside: |
              const $RETRYABLE = $ERR && ($ERR.code === "EINVAL" || $ERR.code === "ENOENT");
              ...
    metadata:
      ghsa: GHSA-7FCC-CW49-XM78
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-7FCC-CW49-XM78
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: windows-shell-fallback-after-spawn-error
  - id: ghsa-7ggg-pvrf-458v.openclaw-host-exec-python-index-override
    message: Request-scoped host exec env overrides include Python package index redirect variables (PIP_*_INDEX, UV_*_INDEX) that can reroute package downloads.
    languages:
      - typescript
      - javascript
    severity: ERROR
    patterns:
      - pattern-either:
          - pattern: |
              sanitizeHostExecEnv({
                ...,
                overrides: {
                  ...,
                  PIP_INDEX_URL: $VALUE,
                  ...
                },
                ...
              })
          - pattern: |
              sanitizeHostExecEnv({
                ...,
                overrides: {
                  ...,
                  PIP_PYPI_URL: $VALUE,
                  ...
                },
                ...
              })
          - pattern: |
              sanitizeHostExecEnv({
                ...,
                overrides: {
                  ...,
                  PIP_EXTRA_INDEX_URL: $VALUE,
                  ...
                },
                ...
              })
          - pattern: |
              sanitizeHostExecEnv({
                ...,
                overrides: {
                  ...,
                  UV_INDEX: $VALUE,
                  ...
                },
                ...
              })
          - pattern: |
              sanitizeHostExecEnv({
                ...,
                overrides: {
                  ...,
                  UV_INDEX_URL: $VALUE,
                  ...
                },
                ...
              })
          - pattern: |
              sanitizeHostExecEnv({
                ...,
                overrides: {
                  ...,
                  UV_DEFAULT_INDEX: $VALUE,
                  ...
                },
                ...
              })
          - pattern: |
              sanitizeHostExecEnv({
                ...,
                overrides: {
                  ...,
                  UV_EXTRA_INDEX_URL: $VALUE,
                  ...
                },
                ...
              })
          - pattern: |
              sanitizeHostExecEnvWithDiagnostics({
                ...,
                overrides: {
                  ...,
                  PIP_INDEX_URL: $VALUE,
                  ...
                },
                ...
              })
          - pattern: |
              sanitizeHostExecEnvWithDiagnostics({
                ...,
                overrides: {
                  ...,
                  PIP_PYPI_URL: $VALUE,
                  ...
                },
                ...
              })
          - pattern: |
              sanitizeHostExecEnvWithDiagnostics({
                ...,
                overrides: {
                  ...,
                  PIP_EXTRA_INDEX_URL: $VALUE,
                  ...
                },
                ...
              })
          - pattern: |
              sanitizeHostExecEnvWithDiagnostics({
                ...,
                overrides: {
                  ...,
                  UV_INDEX: $VALUE,
                  ...
                },
                ...
              })
          - pattern: |
              sanitizeHostExecEnvWithDiagnostics({
                ...,
                overrides: {
                  ...,
                  UV_INDEX_URL: $VALUE,
                  ...
                },
                ...
              })
          - pattern: |
              sanitizeHostExecEnvWithDiagnostics({
                ...,
                overrides: {
                  ...,
                  UV_DEFAULT_INDEX: $VALUE,
                  ...
                },
                ...
              })
          - pattern: |
              sanitizeHostExecEnvWithDiagnostics({
                ...,
                overrides: {
                  ...,
                  UV_EXTRA_INDEX_URL: $VALUE,
                  ...
                },
                ...
              })
    metadata:
      ghsa: GHSA-7GGG-PVRF-458V
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-7GGG-PVRF-458V
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openclaw-host-exec-python-index-override
  - id: ghsa-7h7g-x2px-94hj.openclaw-setup-bootstrap-issued-with-profile-argument
    message: Pairing setup code should issue bootstrap tokens with a dedicated profile object, not ad hoc role/scopes arguments.
    severity: WARNING
    languages:
      - typescript
    patterns:
      - pattern-either:
          - pattern: |
              return {
                ...,
                payload: {
                  ...,
                  bootstrapToken: (await issueDeviceBootstrapToken({
                    baseDir: $DIR,
                    role: $ROLE,
                    scopes: $SCOPES,
                  })).token,
                  ...
                },
                ...
              }
          - pattern: |
              $ISSUED = await issueDeviceBootstrapToken({
                baseDir: $DIR,
                role: $ROLE,
                scopes: $SCOPES,
              })
              ...
              return { ..., payload: { ..., bootstrapToken: $ISSUED.token, ... }, ... }
    metadata:
      ghsa: GHSA-7H7G-X2PX-94HJ
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-7H7G-X2PX-94HJ
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openclaw-setup-bootstrap-issued-with-profile-argument
  - id: ghsa-7jp6-r74r-995q.openclaw-matrix-set-profile-missing-owner-guard
    languages:
      - typescript
    severity: WARNING
    message: Matrix set-profile action dispatches without checking senderIsOwner. See GHSA-7JP6-R74R-995Q.
    metadata:
      ghsa: GHSA-7JP6-R74R-995Q
      category: security
      cwe:
        - CWE-862
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-7JP6-R74R-995Q
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openclaw-matrix-set-profile-missing-owner-guard
    paths:
      include:
        - extensions/matrix/src/actions.ts
        - src/agents/tools/matrix-actions.ts
    patterns:
      - pattern: |
          dispatch({
            action: "setProfile",
            ...
          })
      - pattern-not-inside: |
          if (ctx.senderIsOwner !== true) {
            ...
          }
          ...
  - id: ghsa-7qf6-h84j-8fq4.msteams-safe-fetch-missing-resolvefn
    languages:
      - typescript
    severity: ERROR
    message: MS Teams attachment callers that rely on safeFetch/safeFetchWithPolicy should pass resolveFn so each hostname/redirect hop gets DNS/IP validation instead of only hostname allowlist checks.
    patterns:
      - pattern-either:
          - pattern: |
              safeFetch({
                ...
              })
          - pattern: |
              safeFetchWithPolicy({
                ...
              })
      - pattern-not: |
          safeFetch({
            ...,
            resolveFn: $RESOLVER,
            ...,
          })
      - pattern-not: |
          safeFetchWithPolicy({
            ...,
            resolveFn: $RESOLVER,
            ...,
          })
      - pattern-not-inside: |
          describe(...)
      - pattern-not-inside: |
          it(...)
      - pattern-not-inside: |
          test(...)
      - pattern-not-inside: |
          expect(...)
    metadata:
      ghsa: GHSA-7QF6-H84J-8FQ4
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-7QF6-H84J-8FQ4
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: msteams-safe-fetch-missing-resolvefn
  - id: ghsa-7rcp-mxpq-72pj.oauth-manual-callback-code-only-acceptance
    message: Manual OAuth callback parsing should not accept bare authorization codes because that bypasses CSRF state validation.
    severity: ERROR
    languages:
      - typescript
      - javascript
    patterns:
      - pattern: |
          catch {
            ...
            return { code: $CODE, state: $EXPECTED };
          }
    metadata:
      category: security
      cwe: CWE-352
      ghsa: GHSA-7RCP-MXPQ-72PJ
      rationale: Detects catch blocks in OAuth callback parsers that fabricate a matching state while accepting non-URL code-only input.
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-7RCP-MXPQ-72PJ
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: oauth-manual-callback-code-only-acceptance
  - id: ghsa-7wv4-cc7p-jhxc.openclaw.workspace-dotenv-runtime-guard-incomplete
    languages:
      - typescript
      - javascript
    severity: WARNING
    message: Workspace .env runtime-control blocklist looks incomplete. Guard helpers should block OPENCLAW_GATEWAY_URL/PORT, OPENCLAW_UPDATE_*, OPENCLAW_SKIP_*, and ClawHub/browser-control variables, not just auth keys and _BASE_URL redirects.
    patterns:
      - pattern-either:
          - pattern: |
              const BLOCKED_WORKSPACE_DOTENV_KEYS = new Set([...]);
          - pattern: |
              const BLOCKED_WORKSPACE_DOTENV_KEYS = new Set([...,]);
      - pattern-not-regex: OPENCLAW_GATEWAY_URL
      - pattern-not-regex: OPENCLAW_GATEWAY_PORT
      - pattern-not-regex: OPENCLAW_BROWSER_EXECUTABLE_PATH
      - pattern-not-regex: OPENCLAW_SKIP_
      - pattern-not-regex: OPENCLAW_UPDATE_
      - pattern-not-regex: OPENCLAW_CLAWHUB_
      - pattern-not-regex: CLAWHUB_
    metadata:
      ghsa: GHSA-7WV4-CC7P-JHXC
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-7WV4-CC7P-JHXC
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openclaw.workspace-dotenv-runtime-guard-incomplete
  - id: ghsa-7xmq-g46g-f8pv.openclaw-sandbox-media-deferred-path-read
    message: Sandbox media flows should use root-scoped read helpers at use time instead of deferring to raw bridge/fs pathname reads.
    severity: WARNING
    languages:
      - typescript
      - javascript
    metadata:
      category: security
      ghsa: GHSA-7XMQ-G46G-F8PV
      detector: A
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-7XMQ-G46G-F8PV
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openclaw-sandbox-media-deferred-path-read
    pattern-either:
      - patterns:
          - pattern: |
              $RES = await resolveSandboxedBridgeMediaPath(...);
              ...
              await loadWebMedia($RES.resolved, {
                ...,
                sandboxValidated: true,
                readFile: (filePath) => $BRIDGE.readFile({ filePath, cwd: $ROOT }),
                ...,
              });
          - pattern-not: |
              $RES = await resolveSandboxedBridgeMediaPath(...);
              ...
              await loadWebMedia($RES.resolved, {
                ...,
                sandboxValidated: true,
                readFile: createSandboxBridgeReadFile(...),
                ...,
              });
      - patterns:
          - pattern: |
              return {
                ...,
                sandboxValidated: true,
                readFile: (filePath: string) => fs.readFile(filePath),
                ...,
              };
          - pattern-not: |
              return {
                ...,
                sandboxValidated: true,
                readFile: createRootScopedReadFile(...),
                ...,
              };
  - id: ghsa-82g8-464f-2mv7.openclaw-skill-env-host-injection
    languages:
      - typescript
      - javascript
    message: Skill env overrides are copied into process.env without host-env safety sanitization.
    severity: ERROR
    patterns:
      - pattern-either:
          - pattern: |
              for (const [$KEY, $VALUE] of Object.entries($ENV)) {
                ...
                process.env[$KEY] = $VALUE;
                ...
              }
          - pattern: |
              for (const [$KEY, $VALUE] of Object.entries($ENV)) {
                ...
                $UPDATES.push({ key: $KEY, ... });
                ...
                process.env[$KEY] = $VALUE;
                ...
              }
      - pattern-not-inside: |
          const $SANITIZED = sanitizeSkillEnvOverrides(...);
          ...
      - pattern-not-inside: |
          const $SANITIZED = sanitizeEnvVars(...);
          ...
    metadata:
      ghsa: GHSA-82G8-464F-2MV7
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-82G8-464F-2MV7
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openclaw-skill-env-host-injection
  - id: ghsa-846p-hgpv-vphc.qqbot-outbound-local-read-without-boundary-check
    message: QQ Bot outbound local media handling reads a user-influenced path after resolveQQBotLocalMediaPath() without resolveOutboundMediaPath()/resolveQQBotPayloadLocalFilePath() boundary enforcement.
    severity: ERROR
    languages:
      - typescript
      - javascript
    patterns:
      - pattern-either:
          - pattern: |
              $MP = resolveQQBotLocalMediaPath(normalizePath($RAW));
              ...
              readFileAsync($MP)
          - pattern: |
              $MP = resolveQQBotLocalMediaPath(normalizePath($RAW));
              ...
              audioFileToSilkBase64($MP, ...)
          - pattern: |
              $MP = resolveQQBotLocalMediaPath(normalizePath($RAW));
              ...
              checkFileSize($MP)
      - pattern-not: |
          $RES = resolveOutboundMediaPath($RAW, ..., ...)
          ...
      - pattern-not: |
          $SAFE = resolveQQBotPayloadLocalFilePath($MP)
          ...
      - pattern-not: |
          if (!resolveQQBotPayloadLocalFilePath($MP)) {
            ...
          }
    metadata:
      category: security
      technology:
        - qqbot
      confidence: medium
      ghsa: GHSA-846P-HGPV-VPHC
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-846P-HGPV-VPHC
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: qqbot-outbound-local-read-without-boundary-check
  - id: ghsa-8689-gm9g-jgr6.plivo-v3-replay-key-uses-unsorted-url
    languages:
      - typescript
      - javascript
    severity: ERROR
    message: Plivo V3 replay keys should be derived from the same canonicalized URL+params base used for signature verification, not from the raw verification URL string.
    patterns:
      - pattern-inside: |
          if ($SIG && $NONCE) {
            ...
          }
      - pattern-either:
          - pattern: |
              $REPLAY = `plivo:v3:${sha256Hex(`${$URL}\n${$NONCE}`)}`
          - pattern: |
              $REPLAY = "plivo:v3:" + sha256Hex($URL + "\n" + $NONCE)
          - pattern: |
              $REPLAY = "plivo:v3:" + sha256Hex(`${$URL}\n${$NONCE}`)
      - metavariable-regex:
          metavariable: $URL
          regex: .*(url|verificationUrl|requestUrl|webhookUrl).*
    metadata:
      category: security
      confidence: medium
      ghsa: GHSA-8689-GM9G-JGR6
      detector: A
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-8689-GM9G-JGR6
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: plivo-v3-replay-key-uses-unsorted-url
  - id: ghsa-8cp7-rp8r-mg77.ipv6-transition-special-use-ssrf-guard-bypass
    message: Security-sensitive hostname/IP guard composes isBlockedHostname with isPrivateIpAddress instead of routing through the shared isBlockedHostnameOrIp classifier. Review for missed IPv6 transition encodings such as ISATAP, NAT64, 6to4, or Teredo.
    severity: ERROR
    languages:
      - typescript
      - javascript
    patterns:
      - pattern: isBlockedHostname($HOST)
      - pattern-not: isBlockedHostnameOrIp($HOST)
      - pattern-not-inside: |
          function canFetch(...) {
            ...
          }
    metadata:
      cwe: CWE-918
      ghsa: GHSA-8CP7-RP8R-MG77
      detector_kind: reusable-opengrep
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-8CP7-RP8R-MG77
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: ipv6-transition-special-use-ssrf-guard-bypass
  - id: ghsa-8fmp-37rc-p5g7.openclaw-service-env-merges-unfiltered-dotenv-or-config-env
    languages:
      - typescript
      - javascript
    severity: WARNING
    message: Untrusted config/.env environment variables are merged directly into a managed service environment. Filter startup-control keys (for example NODE_OPTIONS, LD_*, DYLD_*) before embedding them in LaunchAgent/systemd/Scheduled Task environments.
    metadata:
      category: security
      ghsa: GHSA-8FMP-37RC-P5G7
      cwe: CWE-15
      detector: A
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-8FMP-37RC-P5G7
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openclaw-service-env-merges-unfiltered-dotenv-or-config-env
    patterns:
      - pattern-either:
          - pattern: |
              const $ENV = {
                ...$SOURCE,
                ...$REST
              };
          - pattern: |
              const $ENV = {
                ...$PREFIX,
                ...$SOURCE,
                ...$REST
              };
      - metavariable-pattern:
          metavariable: $SOURCE
          patterns:
            - pattern-either:
                - pattern: readStateDirDotEnvVars(...)
                - pattern: collectConfigEnvVars(...)
                - pattern: collectConfigServiceEnvVars(...)
                - pattern: collectConfigRuntimeEnvVars(...)
      - pattern-not-inside: |
          const $SANITIZED = sanitizeHostExecEnvWithDiagnostics(...);
          ...
      - pattern-not-inside: |
          const $SAFE = sanitizeServiceEnvVars(...);
          ...
  - id: ghsa-8jpq-5h99-ff5r.ghsa-8jpq-local-path-media-send
    languages:
      - typescript
      - javascript
    severity: ERROR
    message: Media-send code should not use a local-path classifier to read attacker-controlled paths directly from disk while fetching the same input in the remote branch.
    patterns:
      - pattern-either:
          - pattern: |
              if ($ISLOCAL($INPUT)) {
                ...
                return $FS.readFileSync($PATH);
              } else {
                ...
                $RESPONSE = await fetch($INPUT, ...);
                ...
              }
          - pattern: |
              if ($ISLOCAL($INPUT)) {
                ...
                $DATA = $FS.readFileSync($PATH);
                ...
              } else {
                ...
                $RESPONSE = await fetch($INPUT, ...);
                ...
              }
          - pattern: |
              if ($ISLOCAL($INPUT)) {
                ...
                return await $FS.readFile($PATH);
              }
              ...
              $RESPONSE = await fetch($INPUT, ...);
              ...
          - pattern: |
              if ($ISLOCAL($INPUT)) {
                ...
                $DATA = await $FS.readFile($PATH);
                ...
              }
              ...
              $RESPONSE = await fetch($INPUT, ...);
              ...
    metadata:
      ghsa: GHSA-8JPQ-5H99-FF5R
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-8JPQ-5H99-FF5R
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: ghsa-8jpq-local-path-media-send
  - id: ghsa-8mf7-vv8w-hjr2.openclaw.safebin-profile-lookup-permissive-fallback
    languages:
      - typescript
      - javascript
    severity: ERROR
    message: |
      A safe-bin profile lookup is using a `??` or `||` permissive fallback. The lookup must fail closed: if the binary is missing a profile, deny the call (require user approval) — not allow it with a generic profile. See GHSA-8MF7-VV8W-HJR2.
    metadata:
      category: security
      cwe:
        - CWE-276
        - CWE-77
      ghsas:
        - GHSA-8MF7-VV8W-HJR2
      ghsa: GHSA-8MF7-VV8W-HJR2
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-8MF7-VV8W-HJR2
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openclaw.safebin-profile-lookup-permissive-fallback
    paths:
      include:
        - src/infra/exec-safe-bin-policy*.ts
        - src/infra/exec-approvals*.ts
        - src/infra/exec-allowlist*.ts
        - src/agents/bash-tools.exec*.ts
    pattern-either:
      - patterns:
          - pattern-either:
              - pattern: $PROFILES[$NAME] ?? $FALLBACK
              - pattern: $PROFILES[$NAME] || $FALLBACK
          - metavariable-regex:
              metavariable: $PROFILES
              regex: ^(safeBinProfiles|SAFE_BIN_PROFILES|profiles)$
      - patterns:
          - pattern: $X.$PROFILES[$NAME] ?? $FALLBACK
          - metavariable-regex:
              metavariable: $PROFILES
              regex: ^(safeBinProfiles|SAFE_BIN_PROFILES|profiles)$
  - id: ghsa-92jp-89mq-4374.openclaw-browser-bridge-preauth-helper-route
    message: Privileged browser bridge helper route is registered before auth middleware, so helper access can bypass bridge auth.
    severity: ERROR
    languages:
      - typescript
      - javascript
    patterns:
      - pattern-inside: |
          export async function $F(...){
            ...
          }
      - pattern: |
          app.get($ROUTE, ...)
      - metavariable-regex:
          metavariable: $ROUTE
          regex: ^["'`](?:/sandbox/novnc|/[^"'`]*(?:helper|observer|novnc)[^"'`]*)["'`]$
      - pattern-not-inside: |
          export async function $F(...){
            ...
            installBrowserAuthMiddleware(app, ...)
            ...
            app.get($ROUTE, ...)
            ...
          }
      - pattern-not: |
          app.get($ROUTE, ($REQ, $RES) => {
            if (!hasVerifiedBrowserAuth($REQ)) {
              ...
            }
            ...
          })
    metadata:
      category: security
      technology:
        - express
      confidence: medium
      ghsa: GHSA-92JP-89MQ-4374
      rationale: Helper routes like noVNC observer/token redemption should not be reachable before bridge auth is established.
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-92JP-89MQ-4374
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openclaw-browser-bridge-preauth-helper-route
  - id: ghsa-94pw-c6m8-p9p9.openclaw-gateway-config-mutation-guard-missing-dangerous-flag-diff
    languages:
      - typescript
    severity: ERROR
    message: assertGatewayConfigMutationAllowed() does not compare dangerous config flags using collectEnabledInsecureOrDangerousFlags(). Gateway config.apply/config.patch can otherwise enable dangerous settings through a write-scoped gateway tool. See GHSA-94PW-C6M8-P9P9.
    metadata:
      ghsa: GHSA-94PW-C6M8-P9P9
      category: security
      cwe:
        - CWE-266
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-94PW-C6M8-P9P9
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openclaw-gateway-config-mutation-guard-missing-dangerous-flag-diff
    paths:
      include:
        - src/agents/tools/gateway-tool.ts
    patterns:
      - pattern: |
          function assertGatewayConfigMutationAllowed($PARAMS: $TYPE) {
            ...
          }
      - pattern-not: |
          function assertGatewayConfigMutationAllowed($PARAMS: $TYPE) {
            ...
            collectEnabledInsecureOrDangerousFlags(...)
            ...
          }
  - id: ghsa-9528-x887-j2fp.openclaw-webhook-signature-missing-auth-rate-limit
    languages:
      - typescript
    severity: WARNING
    message: Shared-secret webhook verification does not record auth-rate-limit failure on invalid signature. See GHSA-9528-X887-J2FP.
    metadata:
      ghsa: GHSA-9528-X887-J2FP
      category: security
      cwe:
        - CWE-307
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-9528-X887-J2FP
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openclaw-webhook-signature-missing-auth-rate-limit
    paths:
      include:
        - extensions/nextcloud-talk/src/monitor.ts
        - extensions/**/src/**/monitor*.ts
    patterns:
      - pattern: verifyNextcloudTalkSignature(...)
      - pattern-not-inside: |
          ...
          verifyNextcloudTalkSignature(...)
          ...
          $LIM.recordFailure(...)
          ...
  - id: ghsa-98ch-45wp-ch47.openclaw.system-run-approval-binding-portable-normalization-regression
    languages:
      - typescript
    severity: ERROR
    message: normalizeEnvVarKey with portable:true in system-run-approval-binding.ts instead of normalizeHostOverrideEnvVarKey causes approval-integrity gap. See GHSA-98CH-45WP-CH47.
    metadata:
      category: security
      cwe:
        - CWE-178
      ghsas:
        - GHSA-98CH-45WP-CH47
      ghsa: GHSA-98CH-45WP-CH47
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-98CH-45WP-CH47
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openclaw.system-run-approval-binding-portable-normalization-regression
    paths:
      include:
        - src/infra/system-run-approval-binding.ts
    pattern: "normalizeEnvVarKey($KEY, { portable: true })"
  - id: ghsa-98hh-7ghg-x6rq.approval-resolve-call-review
    languages:
      - typescript
      - javascript
    message: Review approval resolution call sites for missing channel-specific approver authorization.
    severity: WARNING
    pattern-either:
      - pattern: |
          await callApprovalMethod("exec.approval.resolve");
      - pattern: |
          await callApprovalMethod("plugin.approval.resolve");
    metadata:
      category: security
      ghsa: GHSA-98HH-7GHG-X6RQ
      detector: A
      note: Reusable review surface for approval-resolution entrypoints; authorization must be verified manually.
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-98HH-7GHG-X6RQ
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: approval-resolve-call-review
  - id: ghsa-9jpj-g8vv-j5mf.oauth-state-reuses-pkce-verifier
    languages:
      - typescript
      - javascript
    severity: ERROR
    message: OAuth state should be generated independently and must not reuse PKCE verifier material.
    patterns:
      - pattern-either:
          - pattern: |
              new URLSearchParams({
                ...,
                state: $PKCE.verifier,
                ...,
              })
          - pattern: |
              new URLSearchParams({
                ...,
                state: verifier,
                ...,
              })
          - pattern: |
              buildAuthUrl(..., $PKCE.verifier, ...)
          - pattern: |
              buildAuthUrl(..., verifier, ...)
    metadata:
      category: security
      confidence: medium
      rationale: Detects OAuth flows that directly reuse PKCE verifier material as the OAuth state token.
      ghsa: GHSA-9JPJ-G8VV-J5MF
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-9JPJ-G8VV-J5MF
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: oauth-state-reuses-pkce-verifier
  - id: ghsa-9q7v-8mr7-g23p.openclaw.marketplace-plugin-download-unguarded-fetch
    languages:
      - typescript
    severity: WARNING
    message: |
      In src/plugins/marketplace.ts, a raw fetch() is used for a marketplace archive URL without going through fetchWithSsrFGuard. A compromised marketplace server could return a URL pointing to internal network services (RFC1918, cloud metadata). Use fetchWithSsrFGuard({ url: archiveUrl, auditContext: "marketplace-plugin-download" }). See GHSA-9Q7V-8MR7-G23P.
    metadata:
      category: security
      cwe:
        - CWE-918
      ghsas:
        - GHSA-9Q7V-8MR7-G23P
      ghsa: GHSA-9Q7V-8MR7-G23P
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-9Q7V-8MR7-G23P
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openclaw.marketplace-plugin-download-unguarded-fetch
    paths:
      include:
        - src/plugins/marketplace.ts
        - src/plugins/marketplace-*.ts
        - src/plugins/plugin-download*.ts
    patterns:
      - pattern: fetch($URL, ...)
      - pattern-not: fetchWithSsrFGuard(...)
      - pattern-not-inside: |
          fetchWithSsrFGuard(...)
  - id: ghsa-9wqx-g2cw-vc7r.matrix-verification-notice-missing-dm-access-gate
    message: sendVerificationNotice is called from a Matrix verification file that does not import resolveMatrixMonitorAccessState — the DM access policy check needed to gate verification notices is missing. Verification notices must be gated on DM access policy or they leak the bot's verification state to non-allowed peers. See GHSA-9WQX-G2CW-VC7R.
    severity: ERROR
    languages:
      - typescript
    metadata:
      ghsa: GHSA-9WQX-G2CW-VC7R
      category: authorization
      cwe:
        - CWE-863
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-9WQX-G2CW-VC7R
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: matrix-verification-notice-missing-dm-access-gate
    paths:
      include:
        - extensions/matrix/src/matrix/monitor/verification-*.ts
    patterns:
      - pattern: sendVerificationNotice(...)
      - pattern-not-inside: |
          import { ..., resolveMatrixMonitorAccessState, ... } from "$X";
          ...
      - pattern-not-inside: |
          import { resolveMatrixMonitorAccessState } from "$X";
          ...
      - pattern-not-inside: |
          import { resolveMatrixMonitorAccessState, ... } from "$X";
          ...
  - id: ghsa-cg6c-q2hx-69h7.plivo-v2-replay-key-uses-full-verification-url
    message: Plivo V2 replay keys should be derived from the signed base URL without the query string; hashing the full verification URL lets query-only variants mint fresh verifiedRequestKey values.
    severity: ERROR
    languages:
      - typescript
      - javascript
    patterns:
      - pattern-either:
          - pattern: |
              const $KEY = `plivo:v2:${sha256Hex(`${$URL}\n${$NONCE}`)}`
          - pattern: |
              const $KEY = "plivo:v2:" + $HASH(`${$URL}\n${$NONCE}`)
      - metavariable-regex:
          metavariable: $URL
          regex: ^(verificationUrl|url)$
    metadata:
      ghsa: GHSA-CG6C-Q2HX-69H7
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-CG6C-Q2HX-69H7
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: plivo-v2-replay-key-uses-full-verification-url
  - id: ghsa-chm2-m3w2-wcxm.googlechat-users-email-allowlist-mutable-principal
    languages:
      - typescript
      - javascript
    severity: WARNING
    message: Google Chat allowlists should not treat users/<email> entries as email matches; that mixes a mutable email principal into a users/<id> identity slot.
    patterns:
      - pattern-either:
          - pattern: |
              $EMAIL && $ENTRY.replace(/^users\//i, "") === $EMAIL
          - pattern: |
              $ENTRY.startsWith("users/") && $EMAIL && $ENTRY.slice("users/".length) === $EMAIL
      - metavariable-regex:
          metavariable: $EMAIL
          regex: .*[Ee]mail.*
    metadata:
      ghsa: GHSA-CHM2-M3W2-WCXM
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-CHM2-M3W2-WCXM
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: googlechat-users-email-allowlist-mutable-principal
  - id: ghsa-cv7m-c9jx-vg7q.openclaw-browser-upload-raw-paths-forwarded
    message: Browser upload/file-chooser code forwards caller-controlled `paths` directly. Upload paths must first be resolved under DEFAULT_UPLOAD_DIR and then forwarded as validated/resolved paths. Raw paths can read arbitrary local files from the Gateway host. See GHSA-CV7M-C9JX-VG7Q.
    languages:
      - typescript
    severity: ERROR
    metadata:
      ghsa: GHSA-CV7M-C9JX-VG7Q
      category: security
      cwe:
        - CWE-22
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-CV7M-C9JX-VG7Q
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openclaw-browser-upload-raw-paths-forwarded
    paths:
      include:
        - src/agents/tools/browser-tool.ts
        - src/browser/routes/agent.act.ts
        - extensions/browser/src/browser/routes/**/*.ts
        - extensions/browser/src/browser/pw-tools-core.interactions.ts
    pattern-regex: ^\s*paths\s*,\s*$
  - id: ghsa-cwf8-44x6-32c2.openclaw-openshell-uploadpath-direct-localpath-upload
    languages:
      - typescript
    severity: ERROR
    message: uploadPathToRemote() passes localPath directly to `openshell sandbox upload`. Uploads must use a symlink-free staged snapshot (tmpDir from stageDirectoryContents) before syncing into the remote sandbox. See GHSA-CWF8-44X6-32C2.
    metadata:
      ghsa: GHSA-CWF8-44X6-32C2
      category: security
      cwe:
        - CWE-22
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-CWF8-44X6-32C2
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openclaw-openshell-uploadpath-direct-localpath-upload
    paths:
      include:
        - extensions/openshell/src/backend.ts
    pattern-regex: private async uploadPathToRemote[\s\S]*?"sandbox",[\s\S]*?"upload",[\s\S]*?localPath,[\s\S]*?remotePath,
  - id: ghsa-cwq8-6f96-g3q4.openclaw-install-scan-fail-open
    languages:
      - typescript
      - javascript
    severity: ERROR
    message: Install flow catches install-source scan failures and continues into an install/write path instead of blocking.
    metadata:
      category: security
      cwe:
        - CWE-636
        - CWE-754
      ghsa: GHSA-CWQ8-6F96-G3Q4
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-CWQ8-6F96-G3Q4
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openclaw-install-scan-fail-open
    patterns:
      - pattern-either:
          - pattern: |
              try {
                ...
                const $SCAN_RESULT = await $SCAN(...);
                ...
              } catch ($ERR) {
                ...
                $LOGGER.warn(...);
                ...
              }
              ...
              return await $INSTALL(...);
          - pattern: |
              try {
                ...
                await $SCAN(...);
                ...
              } catch ($ERR) {
                ...
                $LOGGER.warn(...);
                ...
              }
              ...
              return await $INSTALL(...);
          - pattern: |
              try {
                ...
                const $SCAN_RESULT = await $SCAN(...);
                ...
              } catch ($ERR) {
                ...
                $LOGGER.warn(...);
                ...
              }
              ...
              return $INSTALL(...);
          - pattern: |
              try {
                ...
                await $SCAN(...);
                ...
              } catch ($ERR) {
                ...
                $LOGGER.warn(...);
                ...
              }
              ...
              return $INSTALL(...);
      - metavariable-regex:
          metavariable: $SCAN
          regex: ^(runtime\.)?scan[A-Za-z0-9_]*InstallSource(Runtime)?$
      - metavariable-regex:
          metavariable: $INSTALL
          regex: ^(install|write|copy|proceed)[A-Za-z0-9_]*
  - id: ghsa-cxpw-2g23-2vgw.acp-extract-text-from-prompt-without-size-limit
    languages:
      - typescript
    message: ACP prompt handlers should pass an explicit byte limit into extractTextFromPrompt before forwarding the assembled message to chat.send.
    severity: ERROR
    pattern-regex: (?s)async\s+prompt\s*\([^)]*\)\s*[:{][\s\S]*?extractTextFromPrompt\s*\([^,)]*\)(?!\s*,)
    metadata:
      ghsa: GHSA-CXPW-2G23-2VGW
      cwe:
        - CWE-20
        - CWE-400
      category: security
      technology:
        - openclaw
        - acp
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-CXPW-2G23-2VGW
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: acp-extract-text-from-prompt-without-size-limit
  - id: ghsa-f5mf-3r52-r83w.zalouser-dangerous-group-name-auth-match
    message: Group authorization candidates include mutable group name or slug values without an explicit opt-in, which can let authorization depend on attacker-controlled naming instead of stable ids.
    severity: ERROR
    languages:
      - typescript
      - javascript
    patterns:
      - pattern-either:
          - pattern: |
              buildZalouserGroupCandidates({
                ...,
                groupName: $GROUP_NAME,
                ...,
              })
          - pattern: |
              buildZalouserGroupCandidates({
                ...,
                groupChannel: $GROUP_CHANNEL,
                ...,
              })
      - pattern-not: |
          buildZalouserGroupCandidates({
            ...,
            allowNameMatching: $ALLOW,
            ...,
          })
      - pattern-not-inside: |
          if (isZalouserDangerousNameMatchingEnabled(...)) {
            ...
          }
      - pattern-not-inside: |
          const $FLAG = isZalouserDangerousNameMatchingEnabled(...);
          ...
          buildZalouserGroupCandidates({
            ...,
            allowNameMatching: $FLAG,
            ...,
          })
    metadata:
      ghsa: GHSA-F5MF-3R52-R83W
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-F5MF-3R52-R83W
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: zalouser-dangerous-group-name-auth-match
  - id: ghsa-f7fh-qg34-x2xh.openclaw-direct-cdp-websocket-top-level-branch-missing-validation
    languages:
      - typescript
      - javascript
    severity: ERROR
    message: createTargetViaCdp() has a top-level direct WebSocket branch that assigns opts.cdpUrl to wsUrl without validating it first. Direct CDP ws:// targets must be checked with assertCdpEndpointAllowed() to prevent second-hop SSRF. See GHSA-F7FH-QG34-X2XH.
    metadata:
      ghsa: GHSA-F7FH-QG34-X2XH
      category: security
      cwe:
        - CWE-918
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-F7FH-QG34-X2XH
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openclaw-direct-cdp-websocket-top-level-branch-missing-validation
    paths:
      include:
        - extensions/browser/src/browser/cdp.ts
    pattern-regex: (?m)^\s*if\s*\(isWebSocketUrl\(opts\.cdpUrl\)\)\s*\{(?:\n\s*//[^\n]*)?\n\s*wsUrl\s*=\s*opts\.cdpUrl\s*;
  - id: ghsa-fg3m-vhrr-8gj6.windows-shell-fallback-retry
    languages:
      - typescript
      - javascript
    severity: ERROR
    message: Windows retry logic that converts wrapper-launch errors into shell execution can reinterpret argv via cmd.exe. Prefer fail-closed wrapper resolution.
    patterns:
      - pattern-either:
          - pattern: |
              if (process.platform === "win32" && $CHECK($ERR)) {
                ...
                return await $RUN(..., true);
              }
          - pattern: |
              if (process.platform === "win32" && $CODE && $SET.has($CODE)) {
                ...
                return await $RUN(..., true);
              }
    metadata:
      ghsa: GHSA-FG3M-VHRR-8GJ6
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-FG3M-VHRR-8GJ6
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: windows-shell-fallback-retry
  - id: ghsa-fh3f-q9qw-93j9.sandbox-config-sha1-hash
    message: Security-sensitive sandbox/config hash helper uses deprecated SHA-1.
    severity: WARNING
    languages:
      - typescript
      - javascript
    patterns:
      - pattern: $CRYPTO.createHash("sha1")
      - pattern-either:
          - pattern-inside: |
              function $F(...){
                ...
                $PAYLOAD = JSON.stringify(...);
                ...
                return ...;
              }
          - pattern-inside: |
              const $F = (...) => {
                ...
                $PAYLOAD = JSON.stringify(...);
                ...
                return ...;
              }
    metadata:
      category: security
      confidence: medium
      technology:
        - nodejs
      ghsa: GHSA-FH3F-Q9QW-93J9
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-FH3F-Q9QW-93J9
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: sandbox-config-sha1-hash
  - id: ghsa-fqcm-97m6-w7rm.openclaw-unconditional-sandboxvalidated-loadwebmedia
    languages:
      - typescript
    severity: WARNING
    message: "loadWebMedia is running with sandboxValidated: true and a direct readFile override without an adjacent sandboxRoot-based fallback to localRoots. This can bypass local media root checks when sandboxRoot is unset."
    patterns:
      - pattern-inside: |
          async function $F(...){
            ...
          }
      - pattern: |
          loadWebMedia($SOURCE, {
            ...,
            sandboxValidated: true,
            ...,
            readFile: ($FILE) => $READ,
            ...,
          })
      - pattern-not-inside: |
          const $MEDIA = $COND
            ? await loadWebMedia($SOURCE, {
                ...,
                sandboxValidated: true,
                ...,
              })
            : await loadWebMedia($SOURCE, {
                ...,
                localRoots: $ROOTS,
                ...,
              });
      - pattern-not-inside: |
          if ($COND) {
            ...
            await loadWebMedia($SOURCE, {
              ...,
              sandboxValidated: true,
              ...,
            });
            ...
          } else {
            ...
            await loadWebMedia($SOURCE, {
              ...,
              localRoots: $ROOTS,
              ...,
            });
            ...
          }
    metadata:
      ghsa: GHSA-FQCM-97M6-W7RM
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-FQCM-97M6-W7RM
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openclaw-unconditional-sandboxvalidated-loadwebmedia
  - id: ghsa-fqrj-m88p-qf3v.openclaw-zalo-replay-dedupe-key-missing-target-scope
    languages:
      - typescript
      - javascript
    severity: INFO
    message: Zalo replay dedupe key is built only from event_name and messageId. Replay caches for multi-account webhook targets must include account/path target scope. See GHSA-FQRJ-M88P-QF3V.
    metadata:
      ghsa: GHSA-FQRJ-M88P-QF3V
      category: security
      cwe:
        - CWE-667
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-FQRJ-M88P-QF3V
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openclaw-zalo-replay-dedupe-key-missing-target-scope
    paths:
      include:
        - extensions/zalo/src/**/*.ts
    pattern-either:
      - pattern: const $KEY = `${$UPDATE.event_name}:${messageId}`
      - pattern: const $KEY = `${$UPDATE.event_name}:${$MESSAGE_ID}`
  - id: ghsa-fv94-qvg8-xqpw.ssh-sandbox-upload-missing-symlink-boundary-check
    languages:
      - typescript
      - javascript
    severity: WARNING
    message: SSH sandbox upload creates a tar stream from a local directory without a preceding symlink boundary validation helper, so tar may follow escaping symlinks before upload.
    patterns:
      - pattern-inside: |
          async function $FUNC(...){
            ...
          }
      - pattern: |
          $TAR = spawn("tar", ["-C", $LOCAL, "-cf", "-", "."], ...)
      - pattern: |
          $SSH = spawn($CMD, $ARGS, ...)
      - pattern-not-inside: |
          async function $FUNC(...){
            ...
            await $CHECK($LOCAL);
            ...
            $TAR = spawn("tar", ["-C", $LOCAL, "-cf", "-", "."], ...)
            ...
          }
    metadata:
      category: security
      confidence: medium
      ghsa: GHSA-FV94-QVG8-XQPW
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-FV94-QVG8-XQPW
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: ssh-sandbox-upload-missing-symlink-boundary-check
  - id: ghsa-g353-mgv3-8pcj.feishu-webhook-mode-missing-encrypt-key
    message: Feishu/Lark webhook-mode configuration sets verificationToken without also configuring encryptKey.
    severity: ERROR
    languages:
      - typescript
      - javascript
    metadata:
      category: security
      technology:
        - feishu
        - lark
      confidence: low
      note: Review aid only; misses inherited/defaulted config and may not prove runtime exploitability.
      ghsa: GHSA-G353-MGV3-8PCJ
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-G353-MGV3-8PCJ
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: feishu-webhook-mode-missing-encrypt-key
    patterns:
      - pattern-either:
          - pattern: |
              {
                ...,
                connectionMode: "webhook",
                ...,
                verificationToken: $TOKEN,
                ...
              }
          - pattern: |
              $CFG = {
                ...,
                connectionMode: "webhook",
                ...,
                verificationToken: $TOKEN,
                ...
              }
      - pattern-not: |
          {
            ...,
            encryptKey: $KEY,
            ...
          }
      - pattern-not: |
          $CFG = {
            ...,
            encryptKey: $KEY,
            ...
          }
  - id: ghsa-g86v-f9qv-rh6m.openclaw-missing-discard-ipv6-special-use-range
    languages:
      - typescript
      - javascript
    severity: WARNING
    message: IPv6 special-use blocking set is typed from ipaddr IPv6Range without the runtime "discard" range, so isBlockedSpecialUseIpv6Address can miss 100::/64 discard addresses.
    patterns:
      - pattern-either:
          - patterns:
              - pattern: |
                  const BLOCKED_IPV6_SPECIAL_USE_RANGES = new Set<Ipv6Range>([
                    ...
                  ]);
              - pattern-not: |
                  const BLOCKED_IPV6_SPECIAL_USE_RANGES = new Set<Ipv6Range>([
                    ...,
                    "discard",
                    ...
                  ]);
              - pattern-not-inside: |
                  type $T = $R | "discard";
                  ...
              - pattern-not-inside: |
                  type $T = "discard" | $R;
                  ...
          - patterns:
              - pattern: |
                  const BLOCKED_IPV6_SPECIAL_USE_RANGES = new Set<ReturnType<ipaddr.IPv6["range"]>>([
                    ...
                  ]);
              - pattern-not: |
                  const BLOCKED_IPV6_SPECIAL_USE_RANGES = new Set<ReturnType<ipaddr.IPv6["range"]>>([
                    ...,
                    "discard",
                    ...
                  ]);
          - patterns:
              - pattern: |
                  const BLOCKED_IPV6_SPECIAL_USE_RANGES = new Set<ReturnType<ipaddr.IPv6['range']>>([
                    ...
                  ]);
              - pattern-not: |
                  const BLOCKED_IPV6_SPECIAL_USE_RANGES = new Set<ReturnType<ipaddr.IPv6['range']>>([
                    ...,
                    "discard",
                    ...
                  ]);
    metadata:
      ghsa: GHSA-G86V-F9QV-RH6M
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-G86V-F9QV-RH6M
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openclaw-missing-discard-ipv6-special-use-range
  - id: ghsa-g8p2-7wf7-98mq.query-gatewayurl-applied-without-confirmation
    languages:
      - typescript
      - javascript
    severity: ERROR
    message: Untrusted gatewayUrl from URL params/hash is written directly into live gateway settings. Route the value through a pending confirmation flow before reconnecting or applying tokens.
    patterns:
      - pattern-either:
          - patterns:
              - pattern: |
                  $RAW = $PARAMS.get("gatewayUrl");
                  ...
                  if ($RAW != null) {
                    ...
                    applySettings($HOST, { ...$HOST.settings, gatewayUrl: $URL, ... });
                    ...
                  }
              - pattern-not: |
                  $HOST.pendingGatewayUrl = ...
          - patterns:
              - pattern-either:
                  - pattern: $URL = $PARAMS.get("gatewayUrl")
                  - pattern: $URL = ($PARAMS.get("gatewayUrl") ?? "").trim()
              - pattern-inside: |
                  if ($COND) {
                    ...
                    $HOST.settings = { ...$HOST.settings, gatewayUrl: $NEXT, ... };
                    ...
                  }
              - pattern-not-inside: |
                  $HOST.pendingGatewayUrl = ...
    metadata:
      ghsa: GHSA-G8P2-7WF7-98MQ
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-G8P2-7WF7-98MQ
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: query-gatewayurl-applied-without-confirmation
  - id: ghsa-g99v-8hwm-g76g.openclaw-web-search-citation-redirect-private-network-policy
    languages:
      - typescript
      - javascript
    message: Citation redirect resolution should not use a private-network-allowing SSRF policy for HEAD redirect expansion.
    severity: ERROR
    patterns:
      - pattern-either:
          - pattern: |
              withWebToolsNetworkGuard({
                ...,
                init: { method: "HEAD", ... },
                ...,
                policy: { dangerouslyAllowPrivateNetwork: true, ... },
                ...
              }, ...)
          - pattern: |
              fetchWithWebToolsNetworkGuard({
                ...,
                init: { method: "HEAD", ... },
                ...,
                policy: { dangerouslyAllowPrivateNetwork: true, ... },
                ...
              })
          - pattern: |
              withWebToolsNetworkGuard({
                ...,
                init: { method: "HEAD", ... },
                ...,
                policy: $POLICY,
                ...
              }, ...)
          - pattern: |
              fetchWithWebToolsNetworkGuard({
                ...,
                init: { method: "HEAD", ... },
                ...,
                policy: $POLICY,
                ...
              })
      - metavariable-pattern:
          metavariable: $POLICY
          patterns:
            - pattern-either:
                - pattern: WEB_TOOLS_TRUSTED_NETWORK_SSRF_POLICY
                - pattern: TRUSTED_POLICY
    metadata:
      category: security
      cwe: CWE-918
      ghsa: GHSA-G99V-8HWM-G76G
      rationale: HEAD-based citation redirect resolution must not opt into private-network SSRF policy.
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-G99V-8HWM-G76G
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openclaw-web-search-citation-redirect-private-network-policy
  - id: ghsa-gcj7-r3hg-m7w6.replay-key-derived-from-idempotency-header
    message: Replay or dedupe key derived from an idempotency/replay header can let unsigned metadata control request identity.
    severity: WARNING
    languages:
      - typescript
      - javascript
    patterns:
      - pattern-either:
          - pattern: |
              const $TOKEN = $GET(..., $HEADER, ...);
              ...
              if ($TOKEN) {
                ...
                return `...${$TOKEN}...`;
              }
          - pattern: |
              const $TOKEN = $GET(..., $HEADER);
              ...
              if ($TOKEN) {
                ...
                return `...${$TOKEN}...`;
              }
          - pattern: |
              const $TOKEN = $HEADERS[$HEADER];
              ...
              if ($TOKEN) {
                ...
                return `...${$TOKEN}...`;
              }
      - metavariable-regex:
          metavariable: $HEADER
          regex: (?i).*(idempotency|replay|dedupe).*
    metadata:
      category: security
      cwe:
        - CWE-294
        - CWE-345
      ghsa: GHSA-GCJ7-R3HG-M7W6
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-GCJ7-R3HG-M7W6
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: replay-key-derived-from-idempotency-header
  - id: ghsa-gg9v-mgcp-v6m7.openclaw-bootstrap-token-legacy-acceptance-without-profile-record
    languages:
      - typescript
    severity: ERROR
    message: verifyDeviceBootstrapToken() consumes a bootstrap token record without resolving the persisted bootstrap profile. Legacy acceptance does not bind setup codes to issued role/scopes and can allow first-use privilege escalation. See GHSA-GG9V-MGCP-V6M7.
    metadata:
      ghsa: GHSA-GG9V-MGCP-V6M7
      category: security
      cwe:
        - CWE-269
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-GG9V-MGCP-V6M7
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openclaw-bootstrap-token-legacy-acceptance-without-profile-record
    paths:
      include:
        - src/infra/device-bootstrap.ts
    pattern-regex: const \[tokenKey\] = found;
  - id: ghsa-gq9c-wg68-gwj2.browser-writable-output-path-bypasses-resolvewritablepathwithinroot
    languages:
      - typescript
    severity: ERROR
    message: Browser route is using resolvePathWithinRoot for a writable output path. For writable destinations (downloads, traces) use resolveWritablePathWithinRoot which performs symlink-aware canonical parent checks. The lexical-only resolvePathWithinRoot can be defeated by a symlink at the parent dir. See GHSA-GQ9C-WG68-GWJ2.
    metadata:
      ghsa: GHSA-GQ9C-WG68-GWJ2
      category: security
      cwe:
        - CWE-22
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-GQ9C-WG68-GWJ2
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: browser-writable-output-path-bypasses-resolveWritablePathWithinRoot
    paths:
      include:
        - extensions/browser/src/browser/routes/**.ts
        - src/browser/routes/**.ts
      exclude:
        - "**/paths.ts"
        - "**/path-output.ts"
    pattern: resolvePathWithinRoot(...)
  - id: ghsa-h7f7-89mm-pqh6.openclaw-skill-download-targetdir-outside-tools-root
    languages:
      - typescript
      - javascript
    message: Untrusted skill download targetDir resolves outside the per-skill tools root.
    severity: ERROR
    patterns:
      - pattern-either:
          - pattern: |
              function $F(..., $SPEC, ...) {
                ...
                if ($SPEC.targetDir?.trim()) {
                  return resolveUserPath($SPEC.targetDir);
                }
                ...
              }
          - pattern: |
              const $TARGET = $SPEC.targetDir?.trim() ? resolveUserPath($SPEC.targetDir) : $FALLBACK;
      - pattern-not-inside: |
          if (!isWithinDir(...)) {
            ...
          }
      - pattern-not-inside: |
          await assertCanonicalPathWithinBase({
            ...
          })
    metadata:
      ghsa: GHSA-H7F7-89MM-PQH6
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-H7F7-89MM-PQH6
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openclaw-skill-download-targetdir-outside-tools-root
  - id: ghsa-h9xm-j4qg-fvpg.apply-patch-sandbox-hostpath-without-workspace-guard
    languages:
      - typescript
    severity: ERROR
    message: Sandbox apply_patch path resolution should not return sandbox bridge host paths without re-applying assertSandboxPath when workspaceOnly remains enabled.
    patterns:
      - pattern-inside: |
          async function resolvePatchPath(...) {
            ...
          }
      - pattern: |
          if (options.sandbox) {
            const resolved = options.sandbox.bridge.resolvePath({
              ...
            });
            ...
            return {
              resolved: resolved.hostPath,
              ...
            };
          }
      - pattern-not: |
          if (options.sandbox) {
            const resolved = options.sandbox.bridge.resolvePath({
              ...
            });
            await assertSandboxPath({
              filePath: resolved.hostPath,
              cwd: options.cwd,
              root: options.cwd,
              ...
            });
            return {
              resolved: resolved.hostPath,
              ...
            };
          }
    metadata:
      ghsa: GHSA-H9XM-J4QG-FVPG
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-H9XM-J4QG-FVPG
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: apply-patch-sandbox-hostpath-without-workspace-guard
  - id: ghsa-j26j-7qc4-3mrf.teams-file-consent-missing-conversation-binding
    languages:
      - typescript
      - javascript
    severity: WARNING
    message: fileConsent/invoke handlers should bind pending uploads to the invoking conversation before consuming upload state; uploadId-only pending-upload lookup can allow cross-conversation use.
    patterns:
      - pattern-inside: |
          if ($ACTIVITY.type !== "invoke" || $ACTIVITY.name !== "fileConsent/invoke") {
            ...
          }
          ...
      - pattern: |
          const $PENDING = getPendingUpload($UPLOAD_ID);
          ...
          if ($ACTION === "accept" && $UPLOAD_INFO) {
            if ($PENDING) {
              ...
              uploadToConsentUrl({
                ...
              });
              ...
            }
          } else {
            ...
            removePendingUpload($UPLOAD_ID);
          }
      - pattern-not-inside: |
          if ($PENDING) {
            ...
            if (!$INVOKE_CONV || $PENDING_CONV !== $INVOKE_CONV) {
              ...
            }
          }
    metadata:
      confidence: medium
      detector_review: family_candidate
      rationale: Matches Teams fileConsent invoke handlers that both upload and remove pending uploads based on uploadId-controlled lookup without a same-handler conversation-binding guard.
      ghsa: GHSA-J26J-7QC4-3MRF
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-J26J-7QC4-3MRF
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: teams-file-consent-missing-conversation-binding
  - id: ghsa-j425-whc4-4jgc.openclaw-dangerous-host-env-override-pivots
    message: Dangerous host env override pivot reaches host env sanitization boundary or policy.
    severity: ERROR
    languages:
      - json
      - typescript
      - javascript
    pattern-either:
      - patterns:
          - pattern-inside: |
              { ... }
          - pattern-regex: '"(GIT_SSH_COMMAND|GIT_EXEC_PATH|GIT_TEMPLATE_DIR|YARN_RC_FILENAME|CC|CXX|CMAKE_C_COMPILER|CMAKE_CXX_COMPILER|RUSTC_WRAPPER|CARGO_BUILD_RUSTC|CARGO_BUILD_RUSTC_WRAPPER|MAKEFLAGS|MFLAGS)"'
      - patterns:
          - pattern-inside: |
              { ... }
          - pattern-regex: '"(GIT_CONFIG_[A-Z0-9_]+|NPM_CONFIG_[A-Z0-9_]+|CARGO_REGISTRIES_[A-Z0-9_]+|TF_VAR_[A-Z0-9_]+)"'
      - patterns:
          - pattern-either:
              - pattern: |
                  sanitizeHostExecEnv({ ..., overrides: { ..., $KEY: $VALUE, ... }, ... })
              - pattern: |
                  sanitizeSystemRunEnvOverrides({ ..., overrides: { ..., $KEY: $VALUE, ... }, ... })
          - metavariable-regex:
              metavariable: $KEY
              regex: ^(GIT_SSH_COMMAND|GIT_EXEC_PATH|GIT_TEMPLATE_DIR|YARN_RC_FILENAME|CC|CXX|CMAKE_C_COMPILER|CMAKE_CXX_COMPILER|RUSTC_WRAPPER|CARGO_BUILD_RUSTC|CARGO_BUILD_RUSTC_WRAPPER|MAKEFLAGS|MFLAGS|GIT_CONFIG_[A-Z0-9_]+|NPM_CONFIG_[A-Z0-9_]+|CARGO_REGISTRIES_[A-Z0-9_]+|TF_VAR_[A-Z0-9_]+)$
    metadata:
      ghsa: GHSA-J425-WHC4-4JGC
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-J425-WHC4-4JGC
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openclaw-dangerous-host-env-override-pivots
  - id: ghsa-jf25-7968-h2h5.openclaw-nodes-screen-record-outpath-guard-missing
    message: The nodes tool (which contains screen_record) must be wrapped via applyNodesToolWorkspaceGuard, which adds outPath to the pathParamKeys. Without this, screen_record outPath bypasses the workspace boundary. See GHSA-JF25-7968-H2H5.
    severity: ERROR
    languages:
      - typescript
    metadata:
      ghsa: GHSA-JF25-7968-H2H5
      category: security
      cwe:
        - CWE-22
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-JF25-7968-H2H5
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openclaw-nodes-screen-record-outpath-guard-missing
    paths:
      include:
        - src/agents/openclaw-tools.ts
    patterns:
      - pattern: createNodesTool(...)
      - pattern-not-inside: |
          import { ..., applyNodesToolWorkspaceGuard, ... } from "$X";
          ...
      - pattern-not-inside: |
          import { applyNodesToolWorkspaceGuard } from "$X";
          ...
      - pattern-not-inside: |
          import { applyNodesToolWorkspaceGuard, ... } from "$X";
          ...
  - id: ghsa-jfv4-h8mc-jcp8.immediate-process-tree-sigkill
    message: Immediate process-tree SIGKILL inside a termination helper deserves review for missing graceful shutdown and ownership checks.
    severity: WARNING
    languages:
      - typescript
      - javascript
    patterns:
      - pattern-either:
          - pattern: process.kill(-$PID, "SIGKILL")
          - pattern: process.kill(-$PID, 9)
      - pattern-inside: |
          function $F(...) {
            ...
          }
      - metavariable-regex:
          metavariable: $F
          regex: (?i).*(kill|terminate|stop|destroy).*
      - pattern-not-inside: |
          function $F(...) {
            ...
            process.kill(-$PID, "SIGTERM")
            ...
            process.kill(-$PID, "SIGKILL")
            ...
          }
      - pattern-not-inside: |
          function $F(...) {
            ...
            process.kill(-$PID, 0)
            ...
            process.kill(-$PID, "SIGKILL")
            ...
          }
    metadata:
      ghsa: GHSA-JFV4-H8MC-JCP8
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-JFV4-H8MC-JCP8
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: immediate-process-tree-sigkill
  - id: ghsa-jj6q-rrrf-h66h.timing-safe-equal-length-short-circuit
    message: Secret comparison short-circuits on length before timingSafeEqual; hash to a fixed length first or use a fixed-length helper.
    severity: ERROR
    languages:
      - typescript
      - javascript
    patterns:
      - pattern-either:
          - pattern: |
              if ($A.length !== $B.length) {
                ...
                return false;
              }
              ...
              return $CRYPTO.timingSafeEqual($A, $B);
          - pattern: |
              if ($A.length !== $B.length) return false;
              ...
              return $CRYPTO.timingSafeEqual($A, $B);
      - pattern-not: |
          return $CRYPTO.timingSafeEqual($HASH(...), $HASH2(...));
    metadata:
      category: security
      confidence: medium
      ghsa: GHSA-JJ6Q-RRRF-H66H
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-JJ6Q-RRRF-H66H
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: timing-safe-equal-length-short-circuit
  - id: ghsa-jjw7-3vjf-fg5j.openclaw-config-private-key-string-field
    languages:
      - typescript
      - javascript
    message: Config schemas that model a privateKey field as a plain string can bypass secret redaction. Prefer buildSecretInputSchema()/SecretInputSchema and sensitive registration.
    severity: ERROR
    patterns:
      - pattern-either:
          - pattern: |
              privateKey: z.string().optional()
          - pattern: |
              privateKey: z.string()
      - pattern-inside: |
          z.object({
            ...
          })
    metadata:
      ghsa: GHSA-JJW7-3VJF-FG5J
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-JJW7-3VJF-FG5J
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openclaw-config-private-key-string-field
  - id: ghsa-jmm5-fvh5-gf4p.ts-early-length-check-before-timingsafeequal
    message: Early length mismatch return before timingSafeEqual can leak secret length; hash or pad to fixed-length before comparing.
    severity: ERROR
    languages:
      - typescript
      - javascript
    patterns:
      - pattern-inside: |
          function $F(...){
            ...
          }
      - pattern-either:
          - pattern: |
              const $A = Buffer.from($LEFT, ...);
              const $B = Buffer.from($RIGHT, ...);
              if ($A.length !== $B.length) {
                return false;
              }
              ...
              return timingSafeEqual($A, $B);
          - pattern: |
              const $A = Buffer.from($LEFT, ...);
              const $B = Buffer.from($RIGHT, ...);
              if ($A.length !== $B.length) return false;
              ...
              return timingSafeEqual($A, $B);
    metadata:
      category: security
      cwe:
        - CWE-208
      ghsa: GHSA-JMM5-FVH5-GF4P
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-JMM5-FVH5-GF4P
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: ts-early-length-check-before-timingsafeequal
  - id: ghsa-jp4j-q5fc-58gv.discord-component-missing-group-policy
    languages:
      - typescript
    message: Discord component ingress calls ensureGuildComponentMemberAllowed without groupPolicy, which skips guild/channel group policy enforcement.
    severity: ERROR
    patterns:
      - pattern: |
          await ensureGuildComponentMemberAllowed({
            ...
          })
      - pattern-not: |
          await ensureGuildComponentMemberAllowed({
            ...,
            groupPolicy: $POLICY,
            ...
          })
    metadata:
      ghsa: GHSA-JP4J-Q5FC-58GV
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-JP4J-Q5FC-58GV
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: discord-component-missing-group-policy
  - id: ghsa-jq3f-vjww-8rq7.webhook-body-read-before-secret-validation
    languages:
      - typescript
      - javascript
    severity: ERROR
    message: Webhook handlers that read a request body before extracting the Telegram secret header should be reviewed for pre-auth resource exhaustion.
    patterns:
      - pattern-inside: |
          createServer(($REQ, $RES) => {
            ...
          })
      - pattern: |
          const $BODY = await readJsonBodyWithLimit($REQ, ...);
          ...
          const $RAW = $REQ.headers["x-telegram-bot-api-secret-token"];
      - pattern-not: |
          const $RAW = $REQ.headers["x-telegram-bot-api-secret-token"];
          ...
          if (!hasValidTelegramWebhookSecret(...)) {
            ...
            return;
          }
          ...
          const $BODY = await readJsonBodyWithLimit($REQ, ...);
    metadata:
      ghsa: GHSA-JQ3F-VJWW-8RQ7
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-JQ3F-VJWW-8RQ7
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: webhook-body-read-before-secret-validation
  - id: ghsa-jqpq-mgvm-f9r6.openclaw-project-local-node-modules-bin-prepended-to-path
    languages:
      - typescript
    severity: ERROR
    message: Project-local node_modules/.bin is included in the PATH prepend candidate list. This can allow a malicious workspace to hijack allowlisted command resolution. Project-local bin must be opt-in and append-only. See GHSA-JQPQ-MGVM-F9R6.
    metadata:
      ghsa: GHSA-JQPQ-MGVM-F9R6
      category: security
      cwe:
        - CWE-426
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-JQPQ-MGVM-F9R6
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openclaw-project-local-node-modules-bin-prepended-to-path
    paths:
      include:
        - src/infra/path-env.ts
    pattern-either:
      - pattern: candidates.push(localBinDir)
      - pattern: prepend.push(localBinDir)
  - id: ghsa-m34q-h93w-vg5x.openshell-unsafe-remote-path-normalization
    languages:
      - typescript
    severity: ERROR
    message: OpenShell remote path configs normalized without managed-root enforcement can escape /sandbox or /agent.
    patterns:
      - pattern-either:
          - pattern: |
              remoteWorkspaceDir: $FN(...),
          - pattern: |
              remoteAgentWorkspaceDir: $FN(...),
      - metavariable-regex:
          metavariable: $FN
          regex: ^(?:normalizeRemotePath|cleanRemotePath|path\.posix\.normalize)$
    metadata:
      category: security
      ghsa: GHSA-M34Q-H93W-VG5X
      detector: A
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-M34Q-H93W-VG5X
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openshell-unsafe-remote-path-normalization
  - id: ghsa-m3mh-3mpg-37hw.openclaw-staged-package-install-without-hidden-project-npmrc
    languages:
      - typescript
    message: Running npm install in a copied package directory without first hiding the staged project .npmrc can let attacker-controlled npm config influence install-time tool execution.
    severity: WARNING
    patterns:
      - pattern: |
          $RES = await runCommandWithTimeout(
            ["npm", "install", "--omit=dev", "--silent", "--ignore-scripts"],
            {..., cwd: $STAGE, ...},
          )
      - pattern-not-inside: |
          $HIDDEN = await hideProjectNpmConfigForInstall($STAGE);
          ...
          try {
            ...
            $RES = await runCommandWithTimeout(
              ["npm", "install", "--omit=dev", "--silent", "--ignore-scripts"],
              {..., cwd: $STAGE, ...},
            )
            ...
          } finally {
            await restoreProjectNpmConfigAfterInstall($HIDDEN);
          }
      - pattern-not-inside: |
          $HIDDEN = await hideProjectNpmConfigForInstall($STAGE);
          ...
          try {
            ...
            await runCommandWithTimeout(
              ["npm", "install", "--omit=dev", "--silent", "--ignore-scripts"],
              {..., cwd: $STAGE, ...},
            )
            ...
          } finally {
            await restoreProjectNpmConfigAfterInstall($HIDDEN);
          }
    metadata:
      ghsa: GHSA-M3MH-3MPG-37HW
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-M3MH-3MPG-37HW
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openclaw-staged-package-install-without-hidden-project-npmrc
  - id: ghsa-m69h-jm2f-2pv8.feishu-reaction-chat-type-defaults-to-p2p
    languages:
      - typescript
    severity: WARNING
    message: Synthetic Feishu reaction events must preserve verified chat type instead of defaulting non-group reactions to p2p.
    patterns:
      - pattern-either:
          - pattern: |
              const $TYPE: $CHAT = $EVENT.chat_type === "group" ? "group" : "p2p";
          - pattern: |
              const $TYPE = $EVENT.chat_type === "group" ? "group" : "p2p";
    metadata:
      ghsa: GHSA-M69H-JM2F-2PV8
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-M69H-JM2F-2PV8
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: feishu-reaction-chat-type-defaults-to-p2p
  - id: ghsa-m7x8-2w3w-pr42.ghsa-m7x8-shell-interpolated-gh-api-login
    message: Unvalidated login-like input interpolated into an execSync shell command that invokes gh api users/...
    severity: ERROR
    languages:
      - typescript
      - javascript
    patterns:
      - pattern-either:
          - pattern: |
              execSync(`gh api users/${$LOGIN}`, ...)
          - pattern: |
              execSync(`gh api users/${$LOGIN}...`, ...)
          - pattern: |
              execSync("gh api users/" + $LOGIN, ...)
          - pattern: |
              execSync("gh api users/" + $LOGIN + ..., ...)
          - pattern: |
              execSync('gh api users/' + $LOGIN, ...)
          - pattern: |
              execSync('gh api users/' + $LOGIN + ..., ...)
    metadata:
      ghsa: GHSA-M7X8-2W3W-PR42
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-M7X8-2W3W-PR42
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: ghsa-m7x8-shell-interpolated-gh-api-login
  - id: ghsa-mc68-q9jw-2h3v.openclaw-docker-path-env-shell-interpolation
    languages:
      - typescript
      - javascript
    severity: ERROR
    message: Caller-controlled params.env.PATH is interpolated directly into an `export PATH=...` shell snippet. Pass it via an environment variable and reference the variable from constant shell text instead. See GHSA-MC68-Q9JW-2H3V.
    metadata:
      ghsa: GHSA-MC68-Q9JW-2H3V
      category: security
      cwe:
        - CWE-78
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-MC68-Q9JW-2H3V
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openclaw-docker-path-env-shell-interpolation
    paths:
      include:
        - src/agents/bash-tools.shared.ts
    pattern-regex: "`[^`]*export\\s+PATH=[^`]*\\$\\{params\\.env\\.PATH\\}[^`]*`"
  - id: ghsa-mf5g-6r6f-ghhm.webhook-invalid-token-without-preauth-lockout
    message: Webhook invalid-token branches should enforce a pre-auth lockout or failure budget before returning 401.
    severity: WARNING
    languages:
      - typescript
    patterns:
      - pattern-inside: |
          function $FUNC(...){
            ...
          }
      - pattern: |
          if (!validateToken($TOKEN, $EXPECTED)) {
            ...
            return { ok: false, statusCode: 401, error: "Invalid token" };
          }
      - pattern-not-inside: |
          if ($RATE_LIMITER.isLocked(...)) {
            ...
            return { ok: false, statusCode: 429, error: "Rate limit exceeded" };
          }
      - pattern-not-inside: |
          if (!validateToken($TOKEN, $EXPECTED)) {
            ...
            if ($RATE_LIMITER.recordFailure(...)) {
              ...
              return { ok: false, statusCode: 429, error: "Rate limit exceeded" };
            }
            ...
            return { ok: false, statusCode: 401, error: "Invalid token" };
          }
    metadata:
      category: security
      ghsa: GHSA-MF5G-6R6F-GHHM
      detector: A
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-MF5G-6R6F-GHHM
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: webhook-invalid-token-without-preauth-lockout
  - id: ghsa-mmpf-jwf4-h3qv.shell-git-add-paths-must-use-double-dash
    languages:
      - bash
    severity: ERROR
    message: Passing filenames into git add without a `--` separator can let option-like paths be interpreted as flags. Use `git add -- ...` and avoid piping path text through xargs.
    pattern-either:
      - patterns:
          - pattern: echo "$FILES" | xargs git add
      - patterns:
          - pattern: printf ... | xargs git add
      - patterns:
          - pattern: ... | xargs git add
          - metavariable-regex:
              metavariable: $...
              regex: .*
      - patterns:
          - pattern: git add $FILES
      - patterns:
          - pattern: git add "$FILES"
      - patterns:
          - pattern: git add ${FILES[@]}
      - patterns:
          - pattern: git add "${FILES[@]}"
      - patterns:
          - pattern: git add ${files[@]}
      - patterns:
          - pattern: git add "${files[@]}"
    pattern-not-either:
      - pattern: git add -- $FILES
      - pattern: git add -- "$FILES"
      - pattern: git add -- ${FILES[@]}
      - pattern: git add -- "${FILES[@]}"
      - pattern: git add -- ${files[@]}
      - pattern: git add -- "${files[@]}"
    metadata:
      ghsa: GHSA-MMPF-JWF4-H3QV
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-MMPF-JWF4-H3QV
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: shell-git-add-paths-must-use-double-dash
  - id: ghsa-mp66-rf4f-mhh8.googlechat-app-url-addon-principal-missing-binding
    message: Google Chat app-url webhook auth accepts add-on principals without comparing the token principal to a configured binding.
    severity: ERROR
    languages:
      - typescript
      - javascript
    metadata:
      ghsa: GHSA-MP66-RF4F-MHH8
      detector: A
      category: security
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-MP66-RF4F-MHH8
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: googlechat-app-url-addon-principal-missing-binding
    patterns:
      - pattern: |
          const $OK =
            $PAYLOAD?.email_verified &&
            ($EMAIL === $CHAT_ISSUER || $ADDON_ISSUER_PATTERN.test($EMAIL));
      - pattern-not: |
          const $EXPECTED = $PARAMS.expectedAddOnPrincipal?.trim().toLowerCase();
      - pattern-not: |
          const $EXPECTED = $INPUT.expectedAddOnPrincipal?.trim().toLowerCase();
      - pattern-not: |
          const $EXPECTED = $CFG.expectedAddOnPrincipal?.trim().toLowerCase();
    paths:
      include:
        - "**/*.ts"
        - "**/*.js"
  - id: ghsa-mwxv-35wr-4vvj.openclaw.gateway.api-channels-prefix-auth-gap
    languages:
      - typescript
    message: Gateway plugin routes that protect only /api/channels/* but not the exact /api/channels root can leave the channel namespace auth-bypassable.
    severity: ERROR
    patterns:
      - pattern-inside: |
          if (handlePluginRequest) {
            ...
          }
      - pattern: |
          if ($REQ_PATH.startsWith("/api/channels/")) {
            ...
          }
      - pattern-not: |
          if ($REQ_PATH === "/api/channels" || $REQ_PATH.startsWith("/api/channels/")) {
            ...
          }
    metadata:
      ghsa: GHSA-MWXV-35WR-4VVJ
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-MWXV-35WR-4VVJ
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openclaw.gateway.api-channels-prefix-auth-gap
  - id: ghsa-p4x4-2r7f-wjxg.openclaw-wrapper-carrier-allow-always
    message: Positional shell carrier persists a carried executable without first rejecting shell or dispatch wrappers.
    severity: ERROR
    languages:
      - typescript
      - javascript
    patterns:
      - pattern-either:
          - pattern: |
              const $RESOLUTION = resolveCommandResolutionFromArgv([$CARRIED], $CWD, $ENV);
              ...
              return resolveExecutionTargetCandidatePath($RESOLUTION, $CWD);
          - pattern: |
              const $RESOLUTION = resolveCommandResolutionFromArgv([$CARRIED], $DIR, $ENVIRONMENT);
              ...
              return resolveExecutionTargetCandidatePath($RESOLUTION, $DIR);
      - pattern-not-inside: |
          const $NAME = normalizeExecutableToken($CARRIED);
          ...
          if (isDispatchWrapperExecutable($NAME) || isShellWrapperExecutable($NAME)) {
            return undefined;
          }
          ...
    metadata:
      ghsa: GHSA-P4X4-2R7F-WJXG
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-P4X4-2R7F-WJXG
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openclaw-wrapper-carrier-allow-always
  - id: ghsa-p536-vvpp-9mc8.openclaw.web-fetch-or-media-unbounded-response-read
    languages:
      - typescript
      - javascript
    severity: WARNING
    message: |
      Inside the openclaw web-fetch / media / SSRF-guarded fetch family, calling .text() / .json() / .arrayBuffer() / .blob() etc. directly on a Response that may have come from an untrusted (model- or plugin-controlled) URL can OOM the process if the upstream returns a multi-GB body. Use readResponseWithLimit() / readResponseTextSnippet() (which stream-and-bound) instead. A pre-buffer Content-Length check is not sufficient — the upstream can lie or omit Content-Length.
    metadata:
      category: security
      cwe:
        - CWE-400
      ghsas:
        - GHSA-P536-VVPP-9MC8
        - GHSA-J27P-HQ53-9WGC
      ghsa: GHSA-P536-VVPP-9MC8
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-P536-VVPP-9MC8
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openclaw.web-fetch-or-media-unbounded-response-read
    paths:
      include:
        - src/web-fetch/**
        - src/agents/tools/web-fetch*.ts
        - src/agents/tools/**/web-fetch*.ts
        - src/plugins/web-fetch-providers*.ts
        - src/media/**
        - src/infra/net/**
      exclude:
        - src/media/read-response-with-limit.ts
        - src/media/read-response-with-limit.test.ts
    patterns:
      - pattern-either:
          - pattern: $RESP.text()
          - pattern: $RESP.json()
          - pattern: $RESP.arrayBuffer()
          - pattern: $RESP.blob()
          - pattern: $RESP.bytes()
          - pattern: $RESP.formData()
      - pattern-not-inside: |
          readResponseTextSnippet($RESP, ...)
      - pattern-not-inside: |
          readResponseWithLimit($RESP, ...)
  - id: ghsa-pfv7-rr5m-qmv6.local-relay-json-endpoint-missing-auth-header-check
    languages:
      - typescript
      - javascript
    severity: WARNING
    message: Local relay servers that expose privileged /json* endpoints should enforce a relay-auth header before serving them.
    patterns:
      - pattern-inside: |
          createServer(($REQ, $RES) => {
            ...
          })
      - pattern-either:
          - pattern: |
              if (($PATH === "/json/version" || $PATH === "/json/version/") && $COND) {
                ...
              }
          - pattern: |
              if ($LIST.has($PATH) && $COND) {
                ...
              }
          - pattern: |
              if ($PATH.startsWith("/json")) {
                ...
              }
      - pattern-not-inside: |
          if ($PATH.startsWith("/json")) {
            ...
            const $TOKEN = ...;
            if (!$TOKEN || $TOKEN !== $AUTH) {
              ...
              return;
            }
            ...
          }
    metadata:
      ghsa: GHSA-PFV7-RR5M-QMV6
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-PFV7-RR5M-QMV6
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: local-relay-json-endpoint-missing-auth-header-check
  - id: ghsa-q2qc-744p-66r2.ghsa-q2qc-post-resolution-agent-prefix-guard
    languages:
      - typescript
      - javascript
    message: Authorization/visibility logic records whether the original session reference was an explicit agent key, then rewrites that reference to a resolved canonical key and later re-checks the rewritten value with startsWith("agent:") instead of using the original explicit-key flag.
    severity: ERROR
    patterns:
      - pattern-inside: |
          const $EXPLICIT = $RAW.startsWith("agent:");
          ...
          $RAW = $RESOLVED;
          ...
          if ($GUARD && !$RAW.startsWith("agent:")) {
            ...
          }
      - metavariable-pattern:
          metavariable: $RESOLVED
          pattern-either:
            - pattern: $OBJ.key
            - pattern: $CALL(...)
      - pattern-not-inside: |
          if ($GUARD && !$EXPLICIT) {
            ...
          }
    metadata:
      ghsa: GHSA-Q2QC-744P-66R2
      category: authz-bypass
      confidence: medium
      detector: A
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-Q2QC-744P-66R2
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: ghsa-q2qc-post-resolution-agent-prefix-guard
  - id: ghsa-q447-rj3r-2cgh.openclaw.webhook-request-stream-read-without-shared-limit-helper
    languages:
      - typescript
    severity: ERROR
    message: Webhook/request handler manually reads request stream data instead of using the shared bounded body helpers. Manual req.on("data") readers often miss unified maxBytes + timeoutMs enforcement and can reintroduce oversized-body or slow-upload DoS. See GHSA-Q447-RJ3R-2CGH.
    metadata:
      ghsa: GHSA-Q447-RJ3R-2CGH
      category: security
      cwe:
        - CWE-400
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-Q447-RJ3R-2CGH
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openclaw.webhook-request-stream-read-without-shared-limit-helper
    paths:
      include:
        - extensions/**/src/**/monitor*.ts
        - extensions/**/src/**/webhook*.ts
        - extensions/**/src/**/nostr-profile-http.ts
        - src/gateway/hooks.ts
        - src/line/**/*.ts
        - src/slack/**/*.ts
        - src/telegram/**/*.ts
      exclude:
        - "**/*.test.ts"
        - src/infra/http-body.ts
        - src/plugin-sdk/**
    patterns:
      - pattern-either:
          - pattern: $REQ.on("data", ...)
          - pattern: $REQ.on('data', ...)
      - metavariable-regex:
          metavariable: $REQ
          regex: ^(req|request|params\.req)$
      - pattern-not-inside: |
          readRequestBodyWithLimit(...)
      - pattern-not-inside: |
          readJsonBodyWithLimit(...)
      - pattern-not-inside: |
          installRequestBodyLimitGuard(...)
  - id: ghsa-q6qf-4p5j-r25g.openclaw.sandbox-image-tool.workspace-only-omission
    languages:
      - typescript
    severity: WARNING
    message: Sandboxed image tool path resolution is using the legacy helper that never enforces tools.fs.workspaceOnly for mounted host paths. This shape is the vulnerable pre-fix image-tool family from GHSA-Q6QF-4P5J-R25G.
    pattern: |
      await resolveSandboxedImagePath({
        sandbox: $SANDBOX,
        imagePath: $IMAGE,
      })
    metadata:
      cwe:
        - CWE-200
        - CWE-284
      ghsa: GHSA-Q6QF-4P5J-R25G
      category: security
      confidence: medium
      rationale: The vulnerable helper only accepted {root, bridge}, so any call to it in sandboxed image loading implies missing workspaceOnly enforcement.
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-Q6QF-4P5J-R25G
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openclaw.sandbox-image-tool.workspace-only-omission
  - id: ghsa-qcj9-wwgw-6gm8.openclaw-workspace-trust-root-env-read
    languages:
      - typescript
      - javascript
    severity: WARNING
    message: Workspace dotenv loading should not be followed by reads of OpenClaw bundled trust-root env vars; block them in the workspace loader instead.
    patterns:
      - pattern-either:
          - pattern: |
              loadWorkspaceDotEnvFile(...)
              ...
              process.env.OPENCLAW_BUNDLED_PLUGINS_DIR
          - pattern: |
              loadWorkspaceDotEnvFile(...)
              ...
              process.env.OPENCLAW_BUNDLED_HOOKS_DIR
          - pattern: |
              loadWorkspaceDotEnvFile(...)
              ...
              process.env.OPENCLAW_BUNDLED_SKILLS_DIR
          - pattern: |
              loadWorkspaceDotEnvFile(...)
              ...
              process.env.OPENCLAW_BROWSER_CONTROL_MODULE
    metadata:
      ghsa: GHSA-QCJ9-WWGW-6GM8
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-QCJ9-WWGW-6GM8
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openclaw-workspace-trust-root-env-read
  - id: ghsa-qf48-qfv4-jjm9.openclaw-extension-upload-direct-file-read-before-sandboxed-media-load
    languages:
      - typescript
      - javascript
    severity: ERROR
    message: Extension upload helper reads a local file path directly before upload. Upload helpers must use sandbox-aware media/path loading (for example loadWebMedia/localRoots/workspace-scoped helpers) so tool callers cannot exfiltrate arbitrary host files through provider uploads. See GHSA-QF48-QFV4-JJM9.
    metadata:
      ghsa: GHSA-QF48-QFV4-JJM9
      category: security
      cwe:
        - CWE-22
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-QF48-QFV4-JJM9
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openclaw-extension-upload-direct-file-read-before-sandboxed-media-load
    paths:
      include:
        - extensions/**/src/**/*.ts
      exclude:
        - "**/*.test.ts"
        - "**/*.spec.ts"
    patterns:
      - pattern-inside: |
          async function $F(...) {
            ...
          }
      - pattern-either:
          - pattern: const $BUF = await fs.readFile($PATH);
          - pattern: const $BUF = await readFile($PATH);
          - pattern: const $BUF = await fsp.readFile($PATH);
      - metavariable-regex:
          metavariable: $F
          regex: (?i).*(resolve.*Upload.*|upload.*(Image|File|Media|Attachment)|.*UploadInput.*|send.*(Image|File|Media|Attachment)).*
      - pattern-not-inside: |
          ...
          loadWebMedia(...)
          ...
      - pattern-not-inside: |
          ...
          resolveStrictExistingPathsWithinRoot(...)
          ...
      - pattern-not-inside: |
          ...
          resolveExistingPathsWithinRoot(...)
          ...
  - id: ghsa-qpjj-47vm-64pj.openclaw-browser-control-routes-missing-auth-middleware
    languages:
      - typescript
    severity: ERROR
    message: Browser control routes are registered without installBrowserAuthMiddleware(). See GHSA-QPJJ-47VM-64PJ.
    metadata:
      ghsa: GHSA-QPJJ-47VM-64PJ
      category: security
      cwe:
        - CWE-306
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-QPJJ-47VM-64PJ
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openclaw-browser-control-routes-missing-auth-middleware
    paths:
      include:
        - extensions/browser/src/server.ts
        - src/browser/server.ts
    patterns:
      - pattern: registerBrowserRoutes(...)
      - pattern-not-inside: |
          ...
          installBrowserAuthMiddleware(...)
          ...
  - id: ghsa-qqq7-4hxc-x63c.openclaw-trusted-tool-media-alias-bypass
    languages:
      - typescript
      - javascript
    severity: ERROR
    message: Exact raw-name registration guards are missing before trusted tool MEDIA paths are preserved.
    patterns:
      - pattern-either:
          - pattern: |
              if (isToolResultMediaTrusted($TOOL, $RESULT)) {
                ...
                return $MEDIA;
              }
          - pattern: |
              if (isToolResultMediaTrusted($TOOL, $RESULT)) return $MEDIA;
      - pattern-not-inside: |
          if (isToolResultMediaTrusted($TOOL, $RESULT)) {
            ...
            if ($NAMES !== undefined) {
              ...
              if (!$RAW || !$NAMES.has($RAW)) {
                ...
                return ...;
              }
            }
            ...
          }
    paths:
      include:
        - src/**/*.ts
        - .artifacts/ghsa-detector-review-runs/**/*.ts
    metadata:
      ghsa: GHSA-QQQ7-4HXC-X63C
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-QQQ7-4HXC-X63C
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openclaw-trusted-tool-media-alias-bypass
  - id: ghsa-qxgf-hmcj-3xw3.raw-image-download-fetch-without-ssrf-guard
    languages:
      - typescript
      - javascript
    severity: ERROR
    message: Image download helper uses raw fetch instead of a shared SSRF-guarded fetch path.
    patterns:
      - pattern-either:
          - pattern: |
              async function $F(...){
                ...
                const $RESP = await fetch($URL, ...);
                ...
              }
          - pattern: |
              const $F = async (...) => {
                ...
                const $RESP = await fetch($URL, ...);
                ...
              }
      - metavariable-regex:
          metavariable: $F
          regex: .*(fetchImage|downloadImage|loadImage|download).*
      - pattern-not-inside: |
          const { response: $RESP, ...$REST } = await fetchWithSsrFGuard(...)
    metadata:
      ghsa: GHSA-QXGF-HMCJ-3XW3
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-QXGF-HMCJ-3XW3
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: raw-image-download-fetch-without-ssrf-guard
  - id: ghsa-r294-2894-92j3.exported-session-html-unsafe-marked-setup
    languages:
      - javascript
    message: Exported session viewer configures Marked renderer callbacks without an html() raw-HTML escape handler; review for stored XSS from untrusted markdown/metadata.
    severity: ERROR
    patterns:
      - pattern: |
          marked.use({
            ...,
            renderer: {
              ...,
            },
            ...,
          })
      - pattern-not: |
          marked.use({
            ...,
            renderer: {
              ...,
              html($TOKEN) {
                return escapeHtml(...);
              },
              ...,
            },
            ...,
          })
      - pattern-not: |
          marked.use({
            ...,
            renderer: {
              ...,
              html($TOKEN) {
                return escapeHtmlTags(...);
              },
              ...,
            },
            ...,
          })
    metadata:
      category: security
      cwe:
        - CWE-79
      ghsa: GHSA-R294-2894-92J3
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-R294-2894-92J3
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: exported-session-html-unsafe-marked-setup
  - id: ghsa-r5h9-vjqc-hq3r.nextcloud-talk-allowlist-display-name-match
    languages:
      - typescript
      - javascript
    message: Nextcloud Talk allowlist checks should compare stable senderId, not mutable senderName/display name.
    severity: ERROR
    patterns:
      - pattern-either:
          - pattern: |
              resolveNextcloudTalkAllowlistMatch({
                ...,
                senderName: $NAME,
                ...
              })
          - pattern: |
              resolveNextcloudTalkGroupAllow({
                ...,
                senderName: $NAME,
                ...
              })
    metadata:
      ghsa: GHSA-R5H9-VJQC-HQ3R
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-R5H9-VJQC-HQ3R
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: nextcloud-talk-allowlist-display-name-match
  - id: ghsa-rchv-x836-w7xp.openclaw-dashboard-auth-query-credentials
    message: Dashboard gateway credentials are being placed into URL query parameters. Use URL fragments/session-only handoff instead, and never propagate the gateway password into browser URLs. See GHSA-RCHV-X836-W7XP.
    severity: ERROR
    languages:
      - swift
    metadata:
      ghsa: GHSA-RCHV-X836-W7XP
      category: security
      cwe:
        - CWE-598
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-RCHV-X836-W7XP
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openclaw-dashboard-auth-query-credentials
    paths:
      include:
        - apps/macos/Sources/OpenClaw/**/*.swift
    pattern-regex: \bqueryItems\s*\.\s*append\s*\(\s*URLQueryItem\s*\(\s*name:\s*"(?:token|password)"
  - id: ghsa-rhfg-j8jq-7v2h.openclaw.extension-configurable-baseurl-raw-fetch-bypasses-ssrf-guard
    languages:
      - typescript
      - javascript
    severity: ERROR
    mode: taint
    message: |
      Channel/provider extension lets an operator/account-configurable URL flow into a raw HTTP client without going through fetchWithSsrFGuard. The configured value can point to a private-network destination (RFC1918, 169.254.169.254 metadata, loopback). See GHSA-RHFG-J8JQ-7V2H. Replace with fetchWithSsrFGuard(...) and thread the account's allowPrivateNetwork through an SsrFPolicy.
      TRIAGE NOTE: This rule only fires when baseUrl/endpoint flows from a params/config/opts-shaped object (i.e. operator- or LLM-supplied input). Hardcoded constants (e.g. `this.baseUrl = "https://api.twilio.com/..."`) are NOT flagged because they are not attacker-controllable. If you see a finding where the URL is verifiably a compile-time constant, it is a false positive — please add a nosem comment and confirm the constant cannot be overridden at runtime.
    metadata:
      category: security
      cwe:
        - CWE-918
      ghsas:
        - GHSA-RHFG-J8JQ-7V2H
      ghsa: GHSA-RHFG-J8JQ-7V2H
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-RHFG-J8JQ-7V2H
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openclaw.extension-configurable-baseurl-raw-fetch-bypasses-ssrf-guard
    paths:
      include:
        - extensions/**/*.ts
        - extensions/**/*.tsx
        - extensions/**/*.js
        - extensions/**/*.mjs
      exclude:
        - extensions/**/*.test.ts
        - extensions/**/*.test.tsx
        - extensions/**/test-harness*
        - extensions/**/*.spec.ts
    pattern-sources:
      - patterns:
          - pattern: |
              const { ..., $URL, ... } = $PARAMS;
          - metavariable-regex:
              metavariable: $URL
              regex: ^(baseUrl|serverUrl|apiBaseUrl|endpoint|host)$|^[a-z][a-zA-Z0-9]*(BaseUrl|BaseURL|ServerUrl|ServerURL|ApiBaseUrl|Endpoint|Host)$
          - pattern-not: |
              const { ..., $URL, ... } = { ... };
          - pattern-not: |
              const { ..., $URL, ... } = $OBJ[$KEY];
      - patterns:
          - pattern: $PARAMS.$URL
          - metavariable-regex:
              metavariable: $URL
              regex: ^(baseUrl|serverUrl|apiBaseUrl|endpoint|host)$|^[a-z][a-zA-Z0-9]*(BaseUrl|BaseURL|ServerUrl|ServerURL|ApiBaseUrl|Endpoint|Host)$
          - metavariable-regex:
              metavariable: $PARAMS
              regex: ^(params|config|options|opts|input|args|cfg|settings|account|credentials|ext)$|^[a-z][a-zA-Z0-9]*(Params|Config|Options|Opts|Input|Args|Cfg|Settings|Account|Credentials|Ext)$
    pattern-sanitizers:
      - pattern: fetchWithSsrFGuard(...)
      - pattern: fetchWithSsrfGuard(...)
      - pattern: $X.fetchWithSsrFGuard(...)
      - pattern: ssrFCheck(...)
      - pattern: validateUrlForSsrF(...)
    pattern-sinks:
      - pattern-either:
          - pattern: fetch($URL, ...)
          - pattern: undiciFetch($URL, ...)
          - pattern: undici.fetch($URL, ...)
          - pattern: $CLIENT.fetch($URL, ...)
          - pattern: axios($URL, ...)
          - pattern: axios.$M($URL, ...)
          - pattern: got($URL, ...)
          - pattern: got.$M($URL, ...)
          - pattern: ky($URL, ...)
          - pattern: wretch($URL)
          - pattern: superagent.$M($URL)
          - pattern: needle.$M($URL, ...)
          - pattern: phin($URL, ...)
          - pattern: http.request($URL, ...)
          - pattern: https.request($URL, ...)
          - pattern: http.get($URL, ...)
          - pattern: https.get($URL, ...)
  - id: ghsa-rm2p-j3r7-4x4j.slack-reaction-handler-missing-system-event-authorization
    languages:
      - typescript
      - javascript
    severity: ERROR
    message: Slack reaction ingress that enqueues system events should first resolve authorizeAndResolveSlackSystemEventContext and bail out when authorization fails.
    patterns:
      - pattern-either:
          - pattern: |
              ctx.app.event("reaction_added", async (...) => {
                ...
                enqueueSystemEvent($TEXT, $OPTS)
                ...
              })
          - pattern: |
              ctx.app.event("reaction_removed", async (...) => {
                ...
                enqueueSystemEvent($TEXT, $OPTS)
                ...
              })
      - pattern-not: |
          ctx.app.event($EVENT, async (...) => {
            ...
            const $CTX = await authorizeAndResolveSlackSystemEventContext(...)
            if (!$CTX) {
              ...
            }
            ...
            enqueueSystemEvent($TEXT, $OPTS)
            ...
          })
    metadata:
      ghsa: GHSA-RM2P-J3R7-4X4J
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-RM2P-J3R7-4X4J
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: slack-reaction-handler-missing-system-event-authorization
  - id: ghsa-rqp8-q22p-5j9q.openclaw-multi-account-plugin-route-replacement
    languages:
      - typescript
      - javascript
    severity: ERROR
    message: "Plugin registers an account-scoped webhook route with replaceExisting: true. Duplicate webhook paths can replace another account's handler and collapse per-account policy context. See GHSA-RQP8-Q22P-5J9Q."
    metadata:
      ghsa: GHSA-RQP8-Q22P-5J9Q
      category: security
      cwe:
        - CWE-284
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-RQP8-Q22P-5J9Q
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openclaw-multi-account-plugin-route-replacement
    paths:
      include:
        - extensions/**/src/**/*.ts
    pattern: |
      registerPluginHttpRoute({
        ...,
        replaceExisting: true,
        ...,
        accountId: $ACCOUNT,
        ...,
      })
  - id: ghsa-rvqr-hrcc-j9vv.unresolved-discovery-routing-from-txt-hints
    languages:
      - typescript
      - javascript
    severity: WARNING
    message: Discovery routing falls back from resolved host/port fields to TXT-only host or port hints, which can let unresolved metadata steer the chosen endpoint.
    patterns:
      - pattern-either:
          - patterns:
              - pattern-either:
                  - pattern: |
                      $HOST = $BEACON.host || $BEACON.tailnetDns || $BEACON.lanHost
                  - pattern: |
                      $HOST = $BEACON.host || $BEACON.lanHost || $BEACON.tailnetDns
                  - pattern: |
                      $HOST = $BEACON.tailnetDns || $BEACON.lanHost || $BEACON.host
                  - pattern: |
                      $HOST = $BEACON.tailnetDns || $BEACON.host || $BEACON.lanHost
                  - pattern: |
                      $HOST = $BEACON.lanHost || $BEACON.host || $BEACON.tailnetDns
                  - pattern: |
                      $HOST = $BEACON.lanHost || $BEACON.tailnetDns || $BEACON.host
                  - pattern: |
                      return $BEACON.host || $BEACON.tailnetDns || $BEACON.lanHost
                  - pattern: |
                      return $BEACON.host || $BEACON.lanHost || $BEACON.tailnetDns
                  - pattern: |
                      return $BEACON.tailnetDns || $BEACON.lanHost || $BEACON.host
                  - pattern: |
                      return $BEACON.tailnetDns || $BEACON.host || $BEACON.lanHost
                  - pattern: |
                      return $BEACON.lanHost || $BEACON.host || $BEACON.tailnetDns
                  - pattern: |
                      return $BEACON.lanHost || $BEACON.tailnetDns || $BEACON.host
              - metavariable-regex:
                  metavariable: $HOST
                  regex: .*(host|Host|targetHost).*
          - patterns:
              - pattern-either:
                  - pattern: |
                      $PORT = $BEACON.port ?? $BEACON.gatewayPort ?? $DEFAULT
                  - pattern: |
                      return $BEACON.port ?? $BEACON.gatewayPort ?? $DEFAULT
              - metavariable-regex:
                  metavariable: $PORT
                  regex: .*(port|Port).*
    metadata:
      confidence: medium
      category: security
      bug-family: unresolved-discovery-routing
      ghsa: GHSA-RVQR-HRCC-J9VV
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-RVQR-HRCC-J9VV
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: unresolved-discovery-routing-from-txt-hints
  - id: ghsa-rwj8-p9vq-25gv.local-media-read-without-root-allowlist
    languages:
      - typescript
      - javascript
    severity: ERROR
    message: A non-HTTP media source is converted with resolveLocalMediaPath(...) and then read from disk without first enforcing a root allowlist validator such as assertLocalMediaPathAllowed.
    metadata:
      ghsa: GHSA-RWJ8-P9VQ-25GV
      cwe: CWE-22
      category: security
      confidence: medium
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-RWJ8-P9VQ-25GV
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: local-media-read-without-root-allowlist
    patterns:
      - pattern: |
          const $LOCAL = resolveLocalMediaPath(...);
          ...
          const $FS = await import("node:fs/promises");
          ...
          const $DATA = await $FS.readFile($LOCAL);
      - pattern-not: |
          const $SAFE = await assertLocalMediaPathAllowed(...);
          ...
          const $DATA = $SAFE.data;
  - id: ghsa-v3j7-34xh-6g3w.loopback-cdp-probe-copies-relay-auth-headers
    message: Loopback CDP discovery/probe code should not merge extension relay auth headers into generic HTTP headers. This can leak a gateway-derived relay token to any local /json/version listener.
    severity: ERROR
    languages:
      - typescript
      - javascript
    patterns:
      - pattern-either:
          - pattern: |
              const $RELAY = $GET($URL);
              ...
              const $MERGED = { ...$RELAY, ...$HEADERS };
          - pattern: |
              const $MERGED = { ...$GET($URL), ...$HEADERS };
      - metavariable-regex:
          metavariable: $GET
          regex: ^(getChromeExtensionRelayAuthHeaders|.*relay.*Headers|.*relay.*Auth.*)$
    metadata:
      category: security
      confidence: medium
      ghsa: GHSA-V3J7-34XH-6G3W
      detector: A
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-V3J7-34XH-6G3W
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: loopback-cdp-probe-copies-relay-auth-headers
  - id: ghsa-v3qc-wrwx-j3pw.openclaw.gateway.config-write.missing-protected-path-guard
    languages:
      - typescript
      - javascript
    severity: ERROR
    message: Sensitive gateway config writes should call assertGatewayConfigMutationAllowed before forwarding config.apply/config.patch.
    patterns:
      - pattern-either:
          - pattern: |
              if ($ACTION === "config.apply") {
                ...
                $RESULT = await callGatewayTool("config.apply", $OPTS, $PARAMS);
                ...
              }
          - pattern: |
              if ($ACTION === "config.patch") {
                ...
                $RESULT = await callGatewayTool("config.patch", $OPTS, $PARAMS);
                ...
              }
      - pattern-not-inside: |
          if ($ACTION === $KIND) {
            ...
            assertGatewayConfigMutationAllowed(...);
            ...
            $RESULT = await callGatewayTool($KIND, $OPTS, $PARAMS);
            ...
          }
    metadata:
      ghsa: GHSA-V3QC-WRWX-J3PW
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-V3QC-WRWX-J3PW
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openclaw.gateway.config-write.missing-protected-path-guard
  - id: ghsa-v6x2-2qvm-6gv8.prompt-hash-secret-falls-back-to-gateway-auth-token
    languages:
      - typescript
      - javascript
    severity: WARNING
    message: Prompt or owner-display hashing secret falls back to gateway auth or remote tokens, reusing an auth secret across trust domains.
    metadata:
      category: security
      confidence: medium
      ghsa: GHSA-V6X2-2QVM-6GV8
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-V6X2-2QVM-6GV8
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: prompt-hash-secret-falls-back-to-gateway-auth-token
    patterns:
      - pattern-either:
          - pattern: |
              ownerDisplaySecret: $CFG?.commands?.ownerDisplaySecret ?? $CFG?.gateway?.auth?.token ?? $CFG?.gateway?.remote?.token
          - pattern: |
              ownerDisplaySecret: $CFG?.commands?.ownerDisplaySecret || $CFG?.gateway?.auth?.token || $CFG?.gateway?.remote?.token
          - pattern: |
              $CFG?.commands?.ownerDisplaySecret?.trim() || $CFG?.gateway?.auth?.token?.trim() || $CFG?.gateway?.remote?.token?.trim()
          - pattern: |
              $X.hashSecret || $X.auth?.token || $X.remoteToken
          - pattern: |
              $X.hashSecret || $X.auth.token || $X.remoteToken
  - id: ghsa-v865-p3gq-hw6m.repeated-decode-without-limit-anomaly-check
    languages:
      - typescript
      - javascript
    severity: WARNING
    message: Repeated path decode loops should enforce a decode-depth anomaly check before treating the path as safe for auth decisions.
    patterns:
      - pattern-inside: |
          function $F(...){
            ...
          }
      - pattern: |
          for (let $PASS = 0; $PASS < $LIMIT; $PASS++) {
            ...
            $NEXT = decodeURIComponent($DECODED);
            ...
          }
      - pattern-not-inside: |
          function $F(...){
            ...
            $ANOMALY = decodeURIComponent($DECODED) !== $DECODED;
            ...
          }
    metadata:
      confidence: medium
      rationale: catches bounded repeated-decode canonicalizers that never fail closed on leftover encodings
      ghsa: GHSA-V865-P3GQ-HW6M
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-V865-P3GQ-HW6M
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: repeated-decode-without-limit-anomaly-check
  - id: ghsa-v8cg-4474-49v8.openclaw-slack-system-event-missing-sender-authorization
    languages:
      - typescript
    severity: WARNING
    message: Slack member/message subtype handler enqueues a system event without first resolving sender authorization via authorizeAndResolveSlackSystemEventContext(). Unauthorized Slack users can otherwise inject trusted system events. See GHSA-V8CG-4474-49V8.
    metadata:
      ghsa: GHSA-V8CG-4474-49V8
      category: security
      cwe:
        - CWE-862
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-V8CG-4474-49V8
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openclaw-slack-system-event-missing-sender-authorization
    paths:
      include:
        - extensions/slack/src/monitor/events/members.ts
        - extensions/slack/src/monitor/events/messages.ts
        - src/slack/monitor/events/members.ts
        - src/slack/monitor/events/messages.ts
    patterns:
      - pattern: enqueueSystemEvent(...)
      - pattern-not-inside: |
          ...
          authorizeAndResolveSlackSystemEventContext(...)
          ...
          enqueueSystemEvent(...)
  - id: ghsa-v8wv-jg3q-qwpq.outbound-media-alias-not-normalized
    languages:
      - typescript
      - javascript
    severity: ERROR
    message: Sandbox media normalization or attachment hydration handles canonical media/path keys but omits mediaUrl/fileUrl aliases, which can bypass local root validation.
    paths:
      include:
        - src/infra/outbound/*.ts
    pattern-either:
      - patterns:
          - pattern: |
              const $KEYS: Array<"media" | "path" | "filePath"> = ["media", "path", "filePath"];
          - pattern-not: |
              const $ANY = ["media", "path", "filePath", "mediaUrl", "fileUrl"]
      - patterns:
          - pattern: |
              const $MEDIA = readStringParam($ARGS, "media", { trim: false });
              ...
              const $FILE =
                readStringParam($ARGS, "path", { trim: false }) ??
                readStringParam($ARGS, "filePath", { trim: false });
          - pattern-not: |
              readStringParam($ARGS, "mediaUrl", { trim: false })
          - pattern-not: |
              readStringParam($ARGS, "fileUrl", { trim: false })
    metadata:
      ghsa: GHSA-V8WV-JG3Q-QWPQ
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-V8WV-JG3Q-QWPQ
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: outbound-media-alias-not-normalized
  - id: ghsa-vfg3-pqpq-93m4.openclaw-tlon-cites-before-final-auth-general
    message: Cite expansion happens before a final DM or channel authorization decision.
    severity: WARNING
    languages:
      - typescript
      - javascript
    patterns:
      - pattern-either:
          - pattern: |
              const $CITED = await resolveAllCites($CONTENT);
              ...
              if (!isDmAllowed($SENDER, $ALLOWLIST)) {
                ...
                return;
              }
          - pattern: |
              const $CITED = await resolveAllCites($CONTENT);
              ...
              const { mode, allowedShips } = resolveChannelAuthorization($CFG, $NEST, $SETTINGS);
              ...
              if (mode === "restricted") {
                ...
                if (!$ALLOWED.includes($SENDER)) {
                  ...
                  return;
                }
              }
    metadata:
      ghsa: GHSA-VFG3-PQPQ-93M4
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-VFG3-PQPQ-93M4
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openclaw-tlon-cites-before-final-auth-general
  - id: ghsa-vfw7-6rhc-6xxg.openclaw.cli-backend-unsanitized-env-merge
    languages:
      - typescript
      - javascript
    severity: ERROR
    message: Unsanitized env merge passed to child-process spawn. Workspace-config-derived env vars can override host vars and lead to code execution. Sanitize via sanitizeHostExecEnv() first. See GHSA-VFW7-6RHC-6XXG.
    metadata:
      ghsa: GHSA-VFW7-6RHC-6XXG
      category: security
      cwe:
        - CWE-77
        - CWE-426
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-VFW7-6RHC-6XXG
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openclaw.cli-backend-unsanitized-env-merge
    patterns:
      - pattern-either:
          - pattern: |
              const $ENV = { ...process.env, ...$BACKEND.env };
          - pattern: |
              const $ENV = Object.assign({}, process.env, $BACKEND.env);
          - pattern: |
              let $ENV = { ...process.env, ...$BACKEND.env };
          - pattern: |
              const $ENV = { ...process.env, ...$BACKEND.env, ...$EXTRA };
      - pattern-either:
          - pattern-inside: |
              function $F(...) {
                ...
                spawn($CMD, $ARGS, { ..., env: $ENV, ... })
                ...
              }
          - pattern-inside: |
              function $F(...) {
                ...
                spawnSync($CMD, $ARGS, { ..., env: $ENV, ... })
                ...
              }
          - pattern-inside: |
              function $F(...) {
                ...
                spawn($CMD, $ARGS, { ..., env: $ENV })
                ...
              }
          - pattern-inside: |
              ($CTX) => {
                ...
                spawn($CMD, $ARGS, { ..., env: $ENV, ... })
                ...
              }
          - pattern-inside: |
              ($CTX) => {
                ...
                return spawn($CMD, $ARGS, { ..., env: $ENV, ... })
                ...
              }
          - pattern-inside: |
              return spawn($CMD, $ARGS, { ..., env: $ENV, ... })
      - pattern-not-inside: |
          $ENV = sanitizeHostExecEnv($X);
  - id: ghsa-vj3g-5px3-gr46.openclaw.untrusted-feishu-key-or-skill-name-into-temp-path-join
    languages:
      - typescript
      - javascript
    severity: WARNING
    message: |
      Untrusted name/identifier from an external source flows into a path.join() call rooted at a temp/sandbox/skill destination, without passing through a validated containment helper. This is the bug class behind CVE-style path-traversal advisories where an attacker-controlled value escapes the intended directory.
    metadata:
      category: security
      cwe:
        - CWE-22
      ghsas:
        - GHSA-VJ3G-5PX3-GR46
        - GHSA-XW4P-PW82-HQR7
      ghsa: GHSA-VJ3G-5PX3-GR46
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-VJ3G-5PX3-GR46
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openclaw.untrusted-feishu-key-or-skill-name-into-temp-path-join
    mode: taint
    pattern-sources:
      - patterns:
          - pattern-either:
              - pattern: $X.imageKey
              - pattern: $X.fileKey
              - pattern: $X.image_key
              - pattern: $X.file_key
              - pattern: |
                  const { ..., imageKey, ... } = $RESP;
              - pattern: |
                  const { ..., fileKey, ... } = $RESP;
              - pattern: |
                  const { ..., image_key, ... } = $RESP;
              - pattern: |
                  const { ..., file_key, ... } = $RESP;
              - pattern: $X.skill.name
              - pattern: $X.skill.id
              - pattern: $X.frontmatter.$Y
    pattern-sanitizers:
      - patterns:
          - pattern-either:
              - pattern: sanitizeTempFileName(...)
              - pattern: withTempDownloadPath(...)
              - pattern: createTempDownloadTarget(...)
              - pattern: resolveSandboxPath(...)
              - pattern: resolvePathWithinRoot(...)
              - pattern: resolveWritablePathWithinRoot(...)
              - pattern: isPathInside(...)
    pattern-sinks:
      - patterns:
          - pattern-either:
              - pattern: path.join($TMP, ...)
              - pattern: path.resolve($TMP, ...)
  - id: ghsa-vmqr-rc7x-3446.openclaw-safe-bins-external-helper-flag
    languages:
      - typescript
      - javascript
    severity: WARNING
    message: safeBins sort profiles must deny --compress-program instead of allowing it as a value-bearing option, because the flag launches an external helper.
    pattern-regex: (?s)sort\s*:\s*\{.*?valueFlags\s*:\s*\[[^\]]*["\']--compress-program["\'][^\]]*\]
    metadata:
      ghsa: GHSA-VMQR-RC7X-3446
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-VMQR-RC7X-3446
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openclaw-safe-bins-external-helper-flag
  - id: ghsa-vvgp-4c28-m3jm.trusted-proxy-control-ui-bypass-without-operator-role
    message: Trusted-proxy Control UI pairing bypass should require an explicit operator-role guard on the trustedProxyAuthOk helper.
    severity: ERROR
    languages:
      - typescript
      - javascript
    patterns:
      - pattern: |
          const $TP =
            isControlUi &&
            ... &&
            $MODE === "trusted-proxy" &&
            ... &&
            $AUTH_METHOD === "trusted-proxy";
      - pattern-not: |
          const $TP =
            isControlUi &&
            ... &&
            $ROLE === "operator" &&
            ... &&
            $MODE === "trusted-proxy" &&
            ... &&
            $AUTH_METHOD === "trusted-proxy";
    metadata:
      ghsa: GHSA-VVGP-4C28-M3JM
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-VVGP-4C28-M3JM
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: trusted-proxy-control-ui-bypass-without-operator-role
  - id: ghsa-vw3h-q6xq-jjm5.websocket-missing-maxpayload-noserver
    languages:
      - typescript
      - javascript
    severity: WARNING
    message: WebSocketServer created with noServer but without maxPayload; unauthenticated oversized frames may reach application parsing.
    patterns:
      - pattern: |
          new WebSocketServer({
            ...,
            noServer: true,
            ...
          })
      - pattern-not: |
          new WebSocketServer({
            ...,
            noServer: true,
            ...,
            maxPayload: $MAX,
            ...
          })
    metadata:
      category: security
      cwe:
        - CWE-400
        - CWE-770
      ghsa: GHSA-VW3H-Q6XQ-JJM5
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-VW3H-Q6XQ-JJM5
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: websocket-missing-maxpayload-noserver
  - id: ghsa-w235-x559-36mg.docker-workspace-mount-ro-guard
    languages:
      - typescript
      - javascript
    severity: WARNING
    message: Workspace bind mount uses a conditional :ro suffix tied to an extra equality check instead of directly enforcing non-rw access.
    patterns:
      - pattern: |
          const $SUFFIX = $ACCESS === "ro" && $SRC === $OTHER ? ":ro" : "";
      - pattern-inside: |
          ...
          $ARGS.push("-v", `${$SRC}:$DEST${$SUFFIX}`)
    metadata:
      category: security
      confidence: medium
      cwe: CWE-250
      ghsa: GHSA-W235-X559-36MG
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-W235-X559-36MG
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: docker-workspace-mount-ro-guard
  - id: ghsa-w235-x559-36mg.docker-workspace-mount-ro-guard-let
    languages:
      - typescript
      - javascript
    severity: WARNING
    message: Workspace bind mount uses a conditional :ro suffix tied to an extra equality check instead of directly enforcing non-rw access.
    patterns:
      - pattern: |
          let $SUFFIX = $ACCESS === "ro" && $SRC === $OTHER ? ":ro" : "";
      - pattern-inside: |
          ...
          $ARGS.push("-v", `${$SRC}:$DEST${$SUFFIX}`)
    metadata:
      category: security
      confidence: medium
      cwe: CWE-250
      ghsa: GHSA-W235-X559-36MG
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-W235-X559-36MG
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: docker-workspace-mount-ro-guard-let
  - id: ghsa-w45g-5746-x9fp.openclaw-unguarded-cron-webhook-fetch
    languages:
      - typescript
      - javascript
    severity: ERROR
    message: Cron webhook delivery should use fetchWithSsrFGuard instead of direct fetch to avoid SSRF bypasses.
    patterns:
      - pattern-inside: |
          if ($TARGET && $EVENT.summary) {
            ...
          }
      - pattern-either:
          - pattern: |
              fetch($TARGET.url, {
                ...
              })
          - pattern: |
              await fetch($TARGET.url, {
                ...
              })
      - pattern-not-inside: |
          fetchWithSsrFGuard({
            ...
          })
      - metavariable-regex:
          metavariable: $TARGET
          regex: .*[Ww]ebhook.*
    metadata:
      category: security
      cwe: "CWE-918: Server-Side Request Forgery (SSRF)"
      ghsa: GHSA-W45G-5746-X9FP
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-W45G-5746-X9FP
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openclaw-unguarded-cron-webhook-fetch
  - id: ghsa-w76h-8m22-hpgh.msteams-shared-link-canonicalization-missing
    message: MSTeams attachment URLs should be canonicalized with tryBuildGraphSharesUrlForSharedLink before direct use as a download candidate URL.
    severity: WARNING
    languages:
      - typescript
      - javascript
    paths:
      include:
        - extensions/msteams/src/attachments/*.ts
    patterns:
      - pattern: |
          return {
            ...,
            url: $URL,
            ...
          };
      - metavariable-pattern:
          metavariable: $URL
          patterns:
            - pattern-either:
                - pattern: contentUrl
                - pattern: $ATT.contentUrl
      - pattern-not-inside: |
          const $GRAPH = tryBuildGraphSharesUrlForSharedLink(...);
          ...
          return {
            ...,
            url: $GRAPH,
            ...
          };
    metadata:
      category: security
      cwe: CWE-918
      ghsa: GHSA-W76H-8M22-HPGH
      rationale: Directly returning MSTeams attachment contentUrl as a download candidate without Graph shared-link canonicalization can bypass the intended media host restrictions.
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-W76H-8M22-HPGH
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: msteams-shared-link-canonicalization-missing
  - id: ghsa-w7j5-j98m-w679.dockerfile-missing-user-directive
    languages:
      - dockerfile
    severity: WARNING
    message: Dockerfile appears to omit any runtime USER directive, so the final runtime user may stay root/default.
    metadata:
      ghsa: GHSA-W7J5-J98M-W679
      detector: A
      category: security
      cwe: CWE-250
      confidence: medium
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-W7J5-J98M-W679
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: dockerfile-missing-user-directive
    paths:
      include:
        - "**/Dockerfile"
        - "**/Dockerfile.*"
      exclude:
        - "**/vendor/**"
    pattern-regex: (?s)\AFROM\b(?:(?!\nUSER\b).)*\Z
  - id: ghsa-w9j9-w4cp-6wgr.openclaw-host-exec-manual-env-merge
    languages:
      - typescript
      - javascript
    severity: WARNING
    message: Manual host-exec env merging that only blocks PATH can miss dangerous interpreter or startup env vars; use centralized host env sanitization.
    patterns:
      - pattern-either:
          - pattern: |
              for (const [$RAW, $VALUE] of Object.entries($OVERRIDES)) {
                ...
                const $KEY = $RAW.trim();
                ...
                const $UPPER = $KEY.toUpperCase();
                ...
                if ($UPPER === "PATH") {
                  continue;
                }
                ...
                $MERGED[$KEY] = $VALUE;
                ...
              }
          - pattern: |
              for (const [$RAW, $VALUE] of Object.entries($OVERRIDES)) {
                ...
                const $UPPER = $RAW.toUpperCase();
                ...
                if ($UPPER === "PATH") {
                  continue;
                }
                ...
                $MERGED[$RAW] = $VALUE;
                ...
              }
      - pattern-not-inside: |
          if (isDangerousHostEnvVarName(...)) {
            ...
          }
      - pattern-not-inside: |
          if (blockedEnvKeys.has(...)) {
            ...
          }
      - pattern-not-inside: |
          if (blockedEnvPrefixes.some(($PREFIX) => ...)) {
            ...
          }
    paths:
      include:
        - "**/*.ts"
        - "**/*.js"
    metadata:
      ghsa: GHSA-W9J9-W4CP-6WGR
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-W9J9-W4CP-6WGR
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openclaw-host-exec-manual-env-merge
  - id: ghsa-wh94-p5m6-mr7j.openclaw-discord-moderation-dispatch-missing-sender-permission-check
    languages:
      - typescript
    severity: WARNING
    message: Discord moderation action dispatches timeout/kick/ban without verifySenderModerationPermission(). See GHSA-WH94-P5M6-MR7J.
    metadata:
      ghsa: GHSA-WH94-P5M6-MR7J
      category: security
      cwe:
        - CWE-862
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-WH94-P5M6-MR7J
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openclaw-discord-moderation-dispatch-missing-sender-permission-check
    paths:
      include:
        - extensions/discord/src/actions/runtime.moderation.ts
        - src/agents/tools/discord-actions-moderation.ts
    patterns:
      - pattern-either:
          - pattern: timeoutMemberDiscord(...)
          - pattern: kickMemberDiscord(...)
          - pattern: banMemberDiscord(...)
      - pattern-not-inside: |
          ...
          verifySenderModerationPermission(...)
          ...
  - id: ghsa-wj55-88gf-x564.queued-node-action-delivery-without-current-policy-recheck
    message: Pending node actions are delivered from the raw queue without current-policy revalidation.
    severity: WARNING
    languages:
      - typescript
      - javascript
    patterns:
      - pattern: |
          const $PENDING = listPendingNodeActions($NODE_ID);
      - pattern-not-inside: |
          const $PENDING = listPendingNodeActions($NODE_ID);
          ...
          const $ALLOWED = $PENDING.filter((entry) => {
            ...
            const $RESULT = isNodeCommandAllowed(...);
            ...
          });
    metadata:
      category: security
      ghsa: GHSA-WJ55-88GF-X564
      bug_family: stale-queued-node-actions
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-WJ55-88GF-X564
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: queued-node-action-delivery-without-current-policy-recheck
  - id: ghsa-wq58-2pvg-5h4f.gateway-http-json-endpoint-missing-required-operator-method
    languages:
      - typescript
      - javascript
    severity: ERROR
    message: Gateway HTTP handlers that call handleGatewayPostJsonEndpoint should set requiredOperatorMethod when the endpoint mutates chat/session state.
    patterns:
      - pattern-either:
          - pattern: |
              handleGatewayPostJsonEndpoint($REQ, $RES, {
                ...,
                pathname: "/v1/chat/completions",
                ...
              })
          - pattern: |
              handleGatewayPostJsonEndpoint($REQ, $RES, {
                ...,
                pathname: "/v1/responses",
                ...
              })
          - pattern: |
              const $HANDLED = await handleGatewayPostJsonEndpoint($REQ, $RES, {
                ...,
                pathname: "/v1/chat/completions",
                ...
              })
          - pattern: |
              const $HANDLED = await handleGatewayPostJsonEndpoint($REQ, $RES, {
                ...,
                pathname: "/v1/responses",
                ...
              })
      - pattern-not: |
          handleGatewayPostJsonEndpoint($REQ, $RES, {
            ...,
            requiredOperatorMethod: $METHOD,
            ...
          })
      - pattern-not: |
          const $HANDLED = await handleGatewayPostJsonEndpoint($REQ, $RES, {
            ...,
            requiredOperatorMethod: $METHOD,
            ...
          })
    metadata:
      category: authorization
      confidence: medium
      review: family-detector
      ghsa: GHSA-WQ58-2PVG-5H4F
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-WQ58-2PVG-5H4F
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: gateway-http-json-endpoint-missing-required-operator-method
  - id: ghsa-x2m8-53h4-6hch.discord-voice-ingress-missing-authorize-review
    message: Discord voice ingress calls agentCommandFromIngress without calling authorizeDiscordVoiceIngress in the same file. See GHSA-X2M8-53H4-6HCH.
    severity: ERROR
    languages:
      - typescript
    metadata:
      ghsa: GHSA-X2M8-53H4-6HCH
      category: authorization
      cwe:
        - CWE-863
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-X2M8-53H4-6HCH
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: discord-voice-ingress-missing-authorize-review
    paths:
      include:
        - extensions/discord/src/voice/**
    patterns:
      - pattern: agentCommandFromIngress(...)
      - pattern-not-inside: |
          import { ..., authorizeDiscordVoiceIngress, ... } from "$X";
          ...
      - pattern-not-inside: |
          import { authorizeDiscordVoiceIngress } from "$X";
          ...
      - pattern-not-inside: |
          import { authorizeDiscordVoiceIngress, ... } from "$X";
          ...
  - id: ghsa-x9cf-3w63-rpq9.openclaw-remote-media-direct-scp-without-source-policy
    languages:
      - typescript
    severity: ERROR
    message: Remote media staging directly scpFile()s `source` from MediaRemoteHost. The source must first be checked against remote attachment roots via isAllowedSourcePath(). See GHSA-X9CF-3W63-RPQ9.
    metadata:
      ghsa: GHSA-X9CF-3W63-RPQ9
      category: security
      cwe:
        - CWE-22
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-X9CF-3W63-RPQ9
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openclaw-remote-media-direct-scp-without-source-policy
    paths:
      include:
        - src/auto-reply/reply/stage-sandbox-media.ts
    pattern-regex: scpFile\(ctx\.MediaRemoteHost,\s*source,\s*dest\)
  - id: ghsa-xhq5-45pm-2gjr.nextcloud-talk-room-name-fallback-match
    message: Nextcloud Talk room authorization must match on the stable roomToken only — display names are collidable across rooms and let an attacker with create-room permission bypass the allowlist by reusing an allowed room's name. See GHSA-XHQ5-45PM-2GJR.
    severity: ERROR
    languages:
      - typescript
      - javascript
    metadata:
      ghsa: GHSA-XHQ5-45PM-2GJR
      category: authorization
      cwe:
        - CWE-863
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-XHQ5-45PM-2GJR
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: nextcloud-talk-room-name-fallback-match
    paths:
      include:
        - extensions/nextcloud-talk/src/**
    patterns:
      - pattern-either:
          - pattern: buildChannelKeyCandidates($TOKEN, $ROOM_NAME, ...)
          - pattern: buildChannelKeyCandidates($TOKEN, ..., normalizeChannelSlug($ROOM_NAME))
          - pattern: buildChannelKeyCandidates($TOKEN, ..., $ROOM_NAME, ...)
  - id: ghsa-xp9r-prpg-373r.openclaw-browser-request-reset-profile-mutation
    languages:
      - typescript
    message: browser.request mutation guards should treat POST /reset-profile like other persistent-profile mutations
    severity: ERROR
    patterns:
      - pattern-either:
          - pattern: |
              if ($METHOD === "POST" && $PATH === "/profiles/create") {
                ...
              }
          - pattern: |
              if ($METHOD === "POST" && $PATH == "/profiles/create") {
                ...
              }
          - pattern: |
              if ($METHOD === "POST" && $PATH === "/profiles/create") return ...;
          - pattern: |
              if ($METHOD === "POST" && $PATH == "/profiles/create") return ...;
      - pattern-not-inside: |
          if (
            $METHOD === "POST" &&
            ($PATH === "/profiles/create" || $PATH === "/reset-profile")
          ) {
            ...
          }
      - pattern-not-inside: |
          if (
            $METHOD == "POST" &&
            ($PATH == "/profiles/create" || $PATH == "/reset-profile")
          ) {
            ...
          }
      - pattern-not: |
          if ($METHOD === "POST" && ($PATH === "/profiles/create" || $PATH === "/reset-profile")) {
            ...
          }
      - pattern-not: |
          if ($METHOD == "POST" && ($PATH == "/profiles/create" || $PATH == "/reset-profile")) {
            ...
          }
    metadata:
      category: security
      cwe: CWE-863
      ghsa: GHSA-XP9R-PRPG-373R
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-XP9R-PRPG-373R
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: openclaw-browser-request-reset-profile-mutation
  - id: ghsa-xwcj-hwhf-h378.media-fetch-logs-unredacted-url
    languages:
      - typescript
      - javascript
    severity: ERROR
    message: Error messages should redact URL values before embedding them in media-fetch failures.
    patterns:
      - pattern-either:
          - pattern: |
              new MediaFetchError($CODE, `Failed to fetch media from ${$URL}: ${...}`)
          - pattern: |
              new MediaFetchError($CODE, `Failed to fetch media from ${$URL}${$REST}: ${...}`)
      - metavariable-pattern:
          metavariable: $URL
          patterns:
            - pattern-not: sourceUrl
            - pattern-not: redactMediaUrl(...)
    metadata:
      category: security
      ghsa: GHSA-XWCJ-HWHF-H378
      detector: A
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-XWCJ-HWHF-H378
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: media-fetch-logs-unredacted-url
  - id: ghsa-xwjm-j929-xq7c.browser-download-route-missing-resolve-writable-output-path
    message: Browser download route handler calls Playwright download without resolving the path through the temp-downloads-root gate. An authenticated CLI/RPC caller can supply a path that traverses outside the temp downloads dir, leading to arbitrary file write. See GHSA-XWJM-J929-XQ7C.
    severity: ERROR
    languages:
      - typescript
    metadata:
      ghsa: GHSA-XWJM-J929-XQ7C
      category: security
      cwe:
        - CWE-22
      advisory-url: https://github.com/openclaw/openclaw/security/advisories/GHSA-XWJM-J929-XQ7C
      detector-bucket: precise
      source-run: 2026-04-17T07-37-10Z
      source-rule-id: browser-download-route-missing-resolve-writable-output-path
    paths:
      include:
        - extensions/browser/src/browser/routes/**.ts
        - src/browser/routes/**.ts
    patterns:
      - pattern-either:
          - pattern: pw.waitForDownloadViaPlaywright(...)
          - pattern: pw.downloadViaPlaywright(...)
      - pattern-not-inside: |
          import { ..., resolveWritableOutputPathOrRespond, ... } from "$X";
          ...
      - pattern-not-inside: |
          import { resolveWritableOutputPathOrRespond } from "$X";
          ...
      - pattern-not-inside: |
          import { resolveWritableOutputPathOrRespond, ... } from "$X";
          ...
      - pattern-not-inside: |
          import { ..., resolvePathWithinRoot, ... } from "$X";
          ...
      - pattern-not-inside: |
          import { resolvePathWithinRoot } from "$X";
          ...
      - pattern-not-inside: |
          import { resolvePathWithinRoot, ... } from "$X";
          ...
  - id: openclaw-policy-raw-http2-connect.no-raw-http2-connect
    languages:
      - typescript
      - javascript
    severity: ERROR
    message: Use connectApnsHttp2Session() from src/infra/push-apns-http2.ts instead of raw http2.connect() so APNs HTTP/2 honors managed proxy policy.
    metadata:
      advisory-id: OPENCLAW-POLICY-RAW-HTTP2-CONNECT
      advisory-url: https://github.com/openclaw/openclaw/pull/74905
      cwe:
        - CWE-441
      category: security
      confidence: HIGH
      detector-bucket: precise
      source-rule-id: no-raw-http2-connect
      source-file: security/opengrep/rules/openclaw-policy/no-raw-http2-connect.yml
    paths:
      include:
        - src/**/*.ts
        - src/**/*.mts
        - src/**/*.js
        - src/**/*.mjs
        - extensions/**/*.ts
        - extensions/**/*.mts
        - extensions/**/*.js
        - extensions/**/*.mjs
      exclude:
        - src/infra/push-apns-http2.ts
        - "**/*.test.ts"
        - "**/*.test.mts"
        - "**/*.test.js"
        - "**/*.test.mjs"
    patterns:
      - pattern: http2.connect(...)
