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.
- 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.
- 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.
- The secret is in a place nobody re-reads. Default credentials live in
dev.envtemplates,values.yamldefaults, 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
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:
- Symmetric JWT secret. One HMAC key signs and verifies. Recover it from source, env template, image, or app bundle, and you forge any token. CVE-2026-48031 is this case.
- Hardcoded private signing key. A private RSA or EC key committed to a repository or baked into an image. The attacker signs assertions, licenses, update manifests, or client certificates the platform trusts. CWE-321 in its purest form.
- Default administrative credential. A fixed username and password in firmware or an installer. CWE-259 (Use of Hard-coded Password). The Juniper and Cisco cases above.
- Embedded API token or service key. A cloud or third-party credential left in a mobile app bundle, browser extension, or client binary, where decompilation hands it over. See the OWASP guidance on hard-coded credentials.
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
- Generate signing keys and credentials per deployment, never ship a default that works. The first boot, the installer, or the orchestration layer mints a unique secret. No two installations share key material.
- Fail closed when the secret is missing or weak. Refuse to start without an operator-supplied secret of real entropy. Do not auto-generate a placeholder, and do not blacklist one literal value while accepting every other weak string. That was the exact gap in CVE-2026-48031.
- Keep secrets out of the artifact. No keys in source, no keys in committed env templates, no keys baked into container layers or mobile bundles. Inject them at runtime from a secrets manager or a mounted volume the artifact never carries.
- Make rotation a supported operation. A leaked or suspected-leaked key must be replaceable without redeploying the product. If rotating the JWT secret means a forced logout, that is acceptable; an unrotatable key is a permanent liability.
- Scan every artifact for secrets in CI, and block on a hit. Run secret-scanning over the repository, the built image layers, and the release bundle. A committed private key or a default password is a failed build, not a warning.
- Audit the supply chain you inherit. Forked boilerplate, base images, and vendored dependencies carry their upstream defaults forward. Re-read the secrets your dependencies ship with, because their default is now your default.
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.
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.
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.
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.
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
- GitHub Advisory Database: CVE-2026-48031 (GHSA-mqq6-462x-jxmm): hardcoded JWT secret in a Go API boilerplate
- MITRE CWE-798: Use of Hard-coded Credentials
- MITRE CWE-321: Use of Hard-coded Cryptographic Key
- MITRE CWE-259: Use of Hard-coded Password
- NVD: CVE-2015-7755 (Juniper ScreenOS unauthorized administrative access)
- NVD: CVE-2018-15439 (Cisco Small Business switches default privileged account)
- OWASP: Use of hard-coded password
- CELVEX Group: Proof Capsule format
- CELVEX Group: Supply-chain validation
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 →