A Stripe price ID (price_1AbC...) hardcoded in an API route handler means the same literal string is duplicated across every checkout flow the AI generated. When the price changes — plan restructuring, annual pricing, regional variants — every scattered reference must be found and updated manually, with no guarantee they all match. CWE-798 applies because the same pattern that scatters price IDs also scatters webhook secrets (whsec_*), which must never appear as literals. OWASP A05 (Security Misconfiguration) covers the broader class: configuration that belongs in a single source of truth spread across the codebase is a maintenance and security misconfiguration by definition.
Medium because scattered price IDs create update-coherence failures and mask webhook secret leaks — the business impact is pricing drift and potential secret exposure rather than immediate data breach.
Centralize all Stripe identifiers in a single config file and import from there. Webhook secrets must always come from environment variables, never literals.
// lib/stripe.ts — single source of truth for all Stripe IDs
export const STRIPE_PRICE_IDS = {
pro_monthly: 'price_1AbCdEfGhIjKlMnOp',
pro_yearly: 'price_1XyZaBcDeFgHiJkLm',
} as const
export const STRIPE_PRODUCT_IDS = {
pro: 'prod_AbCdEfGhIjKlMn',
} as const
// src/app/api/checkout/route.ts
import { STRIPE_PRICE_IDS } from '@/lib/stripe'
const session = await stripe.checkout.sessions.create({
line_items: [{ price: STRIPE_PRICE_IDS.pro_monthly, quantity: 1 }],
})
For whsec_* values: remove the literal immediately and replace with process.env.STRIPE_WEBHOOK_SECRET. Webhook secrets in source code are a secret leak regardless of file location.
ID: ai-slop-hallucinations.asset-references.hardcoded-service-ids-scoped
Severity: medium
What to look for: Walk source files for literal string matches against these service-identifier regex patterns: arn:aws:[a-z0-9-]+:[a-z0-9-]*:[0-9]{12}:[\\w/-]+ (AWS ARN), price_[A-Za-z0-9]{20,} (Stripe price ID), prod_[A-Za-z0-9]{14,} (Stripe product ID), whsec_[A-Za-z0-9]{20,} (Stripe webhook secret PREFIX — flag presence even if not literal secret), re_[A-Za-z0-9]{20,} (Resend API key prefix), ACa[a-f0-9]{32} (Twilio Account SID). For each occurrence, record the file path. Then check whether the file matches one of these allowlisted "config-style" filename patterns: (stripe|billing|plans|pricing|products|payments|subscriptions|tiers)\\.(ts|tsx|js|jsx|mjs|cjs)$, **/config/**, **/constants/**, **/lib/(stripe|billing|payments|aws)/**, *.example, *.test.*, *.spec.*, **/__tests__/**, **/__fixtures__/**. Count all hardcoded service IDs found, total in allowlisted config files, total scattered in non-config files.
Pass criteria: 0 hardcoded service identifiers exist outside of allowlisted config-style files. Report: "X service IDs found, Y in config files, 0 scattered."
Fail criteria: At least 1 hardcoded service identifier appears in a non-config file (e.g., scattered across API route handlers, components, hooks).
Do NOT pass when: A whsec_* (webhook secret) literal appears anywhere in source (even in config files) — webhook secrets must come from env vars, not literals. Flag separately with detail.
Skip (N/A) when: Project has 0 hardcoded service identifiers at all.
Cross-reference: For comprehensive secret detection including AWS keys and API tokens, the Environment Security audit (environment-security) covers credential hygiene.
Detail on fail: "2 scattered hardcoded service IDs: 'price_1AbC...' in src/app/api/checkout/route.ts (move to lib/stripe.ts), 'arn:aws:s3:::user-uploads' in src/components/Uploader.tsx (move to config/aws.ts)"
Remediation: Hardcoded service identifiers scattered across handlers indicate the AI didn't centralize configuration — the same ID appears in 5 different files, and updating it requires hunting all of them down. Centralize them:
// lib/stripe.ts — single source of truth
export const STRIPE_PRICE_IDS = {
pro: 'price_1AbC...',
team: 'price_1XyZ...',
} as const
// src/app/api/checkout/route.ts
import { STRIPE_PRICE_IDS } from '@/lib/stripe'
// use STRIPE_PRICE_IDS.pro instead of the literal
For webhook secrets (whsec_*), never store them as literals — they must always be in environment variables.