← Back to Attack Research

The key was in the box: hardcoded signing keys and default credentials

A product ships with a fixed JWT signing key baked into its source, image, or binary. Anyone who pulls the artifact mints valid tokens and walks in as anyone. CVE-2026-48031 set the secret to the literal string random. Here is the attacker decision tree, why runtime scanners never see it, and the fix that ends the class.

The secret was in the repository the whole time. A widely forked Go API boilerplate signed every authentication token with an HMAC key set to the string random. The default lived in three places at once: the template env file, a code-level fallback, and a mitigation that only ever checked for that one literal value. Pull the public source, read the secret, sign a token that says role: admin, and you are authenticated as anyone on every deployment that took the default. No network exploit. No race condition. The key was published with the product. CVE-2026-48031 is the latest entry in a class that is fifteen years old and shows no sign of ending.

Hardcoded credentials are the cleanest authentication bypass there is. There is no logic flaw to reason about, no parser quirk, no timing window. The product ships with a secret, the secret is the same on every copy, and the secret is recoverable from the artifact. CWE-798 (Use of Hard-coded Credentials) and its cryptographic sibling CWE-321 (Use of Hard-coded Cryptographic Key) describe exactly this. The weakness is rated high-likelihood-of-exploit for a simple reason: once you know the secret, exploitation is deterministic.

This piece walks the class the way our other identity research does. The JWT alg-confusion post showed an attacker forging tokens by abusing the verifier's algorithm dispatch. This one is the blunter cousin: the attacker does not need to confuse the verifier at all, because the signing key is sitting in the artifact. By the end you should be able to reason about where signing keys hide, why your runtime DAST and your network scanner will both report a clean bill of health, and what the artifact-level fix looks like. Verifiable security.

The class in one paragraph

A signing key or a credential is hardcoded when its value is fixed in the shipped artifact rather than generated per deployment. It shows up as a JWT HMAC secret in a config template, a default admin password in firmware, a private key committed to a container image layer, an API token in a mobile app bundle, or a service account password in a Helm chart. The defining property is that the value travels with the software. Every customer who installs the product, and every attacker who downloads the same image, mobile APK, or open-source repository, holds the identical secret. For an asymmetric signing key, possession of the private half lets the attacker sign anything the system will trust. For a symmetric JWT secret, possession of the one shared value lets the attacker both forge and verify. In all variants the consequence is the same: the attacker mints credentials the application accepts as genuine.

CVE-2026-48031 is the textbook instance. The affected package is a popular Go REST API starter kit with over 1,600 GitHub stars. The JWT signing secret defaulted to random in the template env file and via a code-level SetDefault("auth_jwt_secret", "random") fallback. There was even a mitigation: the code refused to start if the secret was literally "random". The problem is that the guard only matched that one string and then auto-generated a non-persistent key, which produced its own failure modes. Anyone running the boilerplate unmodified, or with any weak override, issued forgeable tokens. The fix is to require an operator-supplied secret with real entropy and to fail closed when it is missing.

Why this hides from your scanners

The reason hardcoded keys persist is that the controls most teams rely on are structurally blind to them.

  1. Runtime DAST sees a healthy service. A dynamic scanner hits the login endpoint, gets a token, and the token validates. Everything looks correct, because it is correct from the wire's point of view. The scanner has no way to know that the signing key it would need to forge a token is published in the vendor's public repository. The vulnerability is not a behavior of the running service; it is a property of the artifact that produced it.
  2. Network and version scanning miss it entirely. A banner-grab or CVE-by-version match keys off the running product and its version. A hardcoded secret is frequently a configuration default, not a versioned code path, so two deployments of the identical version differ only in whether the operator changed one line. Version intelligence cannot distinguish them.
  3. The secret is in a place nobody re-reads. Default credentials live in dev.env templates, values.yaml defaults, firmware images, and the third layer of a base container. They were written once, copied forward through every fork and every internal cookbook, and never audited again. The README example omits the warning. The integrator who copied it in 2021 is gone.

Detecting this class requires inspecting the artifact and the source, not probing the endpoint. That is the entire point. You have to look at what shipped.

The attacker decision tree

ATTACKER DECISION TREE Hardcoded Signing Key / Credential ┌──────────────────────────────────────┐ │ 1. Obtain the artifact │ │ - clone the public repo │ │ - pull the container image │ │ - decompile the mobile app │ │ - dump the firmware │ └──────────────┬───────────────────────┘ │ ▼ ┌──────────────────────────────────────┐ │ 2. Extract the key material │ │ - grep for SECRET, KEY, PASSWORD │ │ - read env templates / defaults │ │ - scan image layers (history) │ │ - pull strings from the binary │ └──────────────┬───────────────────────┘ │ ▼ ┌──────────────────────────────────────┐ │ 3. Forge a token or authenticate │ │ a) JWT HMAC secret │ │ → sign {role: admin} with it │ │ b) private signing key │ │ → sign any assertion / cert │ │ c) default admin credential │ │ → log straight in │ └──────────────┬───────────────────────┘ │ ▼ ┌──────────────────────────────────────┐ │ 4. Authenticate as anyone │ │ - sub: │ │ - role / scope: admin │ │ - tenant: │ └──────────────┬───────────────────────┘ │ ▼ ┌──────────────────────────────────────┐ │ 5. Full access, every deployment │ │ that took the default │ └──────────────────────────────────────┘

One key, recovered from the artifact, unlocks every deployment that shipped with the default.

The decisive feature of step 2 is that the attacker does the work once. The recovered key is good against the vendor's entire install base. A single grep through a public repository, a single docker history on a base image, or a single run of strings over a firmware blob produces a secret that works against every customer who never changed it. The economics are brutally favorable to the attacker and brutally unfavorable to the defender who assumes a default is safe.

The class is everywhere, not just JWTs

The JWT case is the cleanest to demonstrate, but the weakness spans every artifact type, and the canonical history makes the point. Network firmware has shipped static administrative credentials for years: CVE-2015-7755 documented an unauthorized administrative-access password baked into Juniper ScreenOS, recoverable by anyone with the firmware. CVE-2018-15439 covered a default privileged account in a line of Cisco Small Business switches that granted full control to anyone who knew it existed. These are the same weakness as the Go boilerplate's random secret, expressed in firmware instead of source: a credential that travels with the product and is identical on every unit.

The variants share a single shape:

What we observe

We are honest about the limits of our visibility. CelvexGroup's continuous validation runs against assets the customer flags into scope, and the always-safe lane we operate is passive recon, version reads, and artifact and source inspection rather than active credential-stuffing against live login pages. Within that scope, across customer-facing software and the public artifacts that produce it, the pattern is consistent: default secrets survive longer than anyone expects, because nothing in the normal pipeline forces them to be changed. A service that runs correctly with the shipped default raises no alarm. The single line that closes the gap, requiring an operator-supplied secret and failing closed when it is absent, is almost always optional in the product and therefore almost always skipped.

What to do about it: the artifact contract

Hardcoded keys are a build-time and ship-time problem, so the controls live there. We summarize them as a contract every artifact you ship or run should satisfy.

Hardcoded-secret contract: six controls that end the class

A default secret that works is a backdoor with a changelog entry. Generate per deployment, fail closed when it is missing, and never let the key travel inside the artifact.

The detection grep, in concrete terms, is the same move the attacker makes, run against your own source and images:

# Source: candidate hardcoded secrets and keys
$ grep -rnE "(SECRET|PASSWORD|PRIVATE_KEY|API_KEY|JWT)" \
    --include="*.go" --include="*.py" --include="*.js" --include="*.env" .

# Committed private keys
$ grep -rn "BEGIN .*PRIVATE KEY" .

# Container image: read every layer's build history
$ docker history --no-trunc 

# Binary / firmware: pull printable strings
$ strings firmware.bin | grep -iE "secret|passwd|-----BEGIN"

Read each hit. Confirm the value is injected at runtime, not shipped. Confirm there is no fallback path that substitutes a default when the real secret is absent. The exercise is finishable in an afternoon for any repository, and it is the only way to find this class, because the running service will never tell you.

How Celvex catches this

Find. Prove. Fix. Verify.

Find

We inspect the artifact and source in scope: public repositories, container image layers, and client bundles, scanning for committed secrets, default signing keys, and the fallback-to-default code paths that survive a partial mitigation.

Prove

For a confirmed hardcoded key, we ship a signed Proof Capsule with the exact file and line, a token forged with the recovered secret, and a replay that authenticates against the customer's own staging.

Fix

The Capsule's remediation block points at the artifact contract: which default to remove, how to inject the secret at runtime, how to fail closed, and which CI secret-scan gate to add.

Verify

After the fix lands, the recovered key no longer signs an accepted token and the secret-scan gate is green. The finding closes automatically and the verified-fix event is recorded for the auditor.

This is squarely in the artifact-and-supply-chain lane, where the evidence is the shipped bytes rather than a live exploit. Our supply-chain validation capability is built for exactly this: proving a property of what shipped, signing the proof, and letting the customer reverify it independently. We do not claim to audit every line of every dependency in a customer's tree. We do claim that when a default signing key or credential is reachable in an artifact in scope, we find it, prove it with a reproducible Capsule, and verify the fix held.

Bottom line

Hardcoded signing keys and default credentials are the simplest authentication bypass that still ships in 2026, because the controls most teams trust cannot see them. Runtime scanners report a healthy service. Version intelligence cannot tell a hardened deployment from a defaulted one. The secret sits in a template, an image layer, or a binary that nobody re-reads, and it is identical on every copy, so one grep against a public artifact arms the attacker against the entire install base. CVE-2026-48031 set the value to random and shipped it three different ways. The fix is not clever: generate per deployment, fail closed when the secret is missing, keep keys out of the artifact, and scan every build. The audit is an afternoon. Until that afternoon, every deployment that took the default is one grep away from full takeover.

Verifiable security. Find it. Prove it. Fix it. Verify the fix held. That is what we ship.

Sources

Find the key before someone else does.

Free Exposure Check, no signup required. We inspect the artifacts in your public footprint for default signing keys and committed credentials, and ship a Proof Capsule for the highest-confidence finding.

Run a Free Scan →