Skip to content

feat(rules): reduce A02-HARDCODED-SECRET false positives on type definitions and UI strings #79

Description

@jeremyjs

Problem

The A02-HARDCODED-SECRET rule produces false positives on:

  1. Type definitions that describe a parameter shape
  2. UI/strings that mention auth concepts (e.g., error messages)
  3. Placeholder values that are intentionally non-functional

Reproduction

1. Type definitions

// packages/wallet-worker/src/config.ts
export interface WalletConfig {
  chain: EvmChain;
  address: `0x${string}`;
  privateKey: `0x${string}`;       // ← flagged: "Hardcoded private key"
  hotWalletAccountId: string;
}

2. UI / error strings

// apps/web/app/partner-invite/[token]/page.tsx
const messages = {
  missing_bearer: "Sign in to accept this invite.",  // ← flagged: "Hardcoded access token"
  invalid_token: "Your session is invalid — please sign in again.",
};

3. Placeholder strings

// apps/web/lib/connect.ts
return JSON.stringify({
  mcpServers: {
    dial: {
      env: {
        DIAL_PRIVATE_KEY: "0xYOUR_PRIVATE_KEY",  // ← flagged: "Hardcoded private key"
      },
    },
  },
});

Current mitigation attempts

The rule already has a placeholder check:

if (/['"`](xxx|placeholder|changeme|your[_-]|example|TODO|REPLACE|<)/i.test(value)) continue;

This catches some patterns but misses:

  • "YOUR_PRIVATE_KEY" (uppercase YOUR, no trailing underscore)
  • "missing_bearer" (the KEY is a UI string key, not a secret value)

Proposed Solutions

Solution 1: Skip type/interface definitions

If the line is inside a type, interface, or generic function signature (contains : before the =, or is inside braces with a : typed field), skip it.

Solution 2: Require sensitive word to be the VALUE, not key/substring

The current bearer regex /(?:access[_-]?token|auth[_-]?token|bearer)\s*[:=]\s*['"][^'"]{8,}['"]/i matches missing_bearer: "Sign in..." because bearer appears anywhere in the line.

Fix: The regex should be more precise, or the code should parse the matched line to verify the sensitive word is part of the secret VALUE, not the key name or a random substring.

Solution 3: Expand placeholder whitelist

Add more placeholder patterns:

  • YOUR_ (with any suffix: YOUR_PRIVATE_KEY, YOUR_API_KEY)
  • <...> (e.g., <REPLACE_WITH_KEY>)
  • [...] (e.g., [INSERT KEY HERE])
  • EXAMPLE, SAMPLE, DEMO

Preference

All three solutions should be implemented together. They're complementary and each addresses a distinct false-positive class.


Reported from Dial-WTF/x402-dial production rollout — PR #120

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions