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

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions