← Back to Feed CACHED · 2026-07-14 09:38:27 · CACHE_KEY tenable:114129
tenable:114129 · CWE-200 · Disclosed 2023-12-11

Tenable WAS 114129 — Generic Secret Disclosure

ASSESSED — NOISGATE V0.5
Vendor
Reassessed
Verdict:
Do you agree?
01 · The Real Story

The scanner didn't find a bug — it found your developers checking AWS keys into JavaScript

Tenable WAS plugin 114129 (Generic Secret Disclosure) is not a CVE and there is no NVD record. It is a *detection signature* in the Tenable Web App Scanning engine, part of the Data Exposure family, first published 2023-12-11 and refreshed 2025-10-21. The check crawls your web application and flags any HTTP response — HTML, inline <script>, sourcemapped JS bundle, or HTML comment — that contains string patterns matching API keys, OAuth client secrets, JWT signing keys, AWS/GCP/Azure access keys, private keys (-----BEGIN), Slack/Stripe/Twilio/SendGrid tokens, database DSNs, or generic high-entropy tokens. Any modern web asset with an unminified React/Vue/Angular bundle, a .env-leaked build, or a copy-pasted curl example in a comment is eligible.

Tenable rates this CVSS v3.0 8.6 (High) and v4.0 8.7 (High) using vector AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N — unauthenticated network attacker, no user interaction, scope change, high confidentiality impact. That score is *directionally correct but structurally deceptive*: the finding itself is trivial to exploit (View Source is the exploit), but the true impact is a step function of what leaked. A leaked Google Analytics measurement ID is noise; a leaked AWS root key, Okta API token, GitHub PAT with repo scope, or Stripe live secret is a fleet-scale incident. Because there is no vendor CVE baseline, this is an initial assessment — treat the plugin verdict as a *pointer to a triage decision*, not a single severity.

"Not a CVE — a scanner signature for hardcoded secrets in client-side code. Verdict floats with what leaked; assume the worst until you triage."
02 · The Attack Path

5 steps from start to impact.

STEP 01

Discover the target surface

Attacker enumerates your public web properties — marketing site, SPA login page, customer portal, status page, employee-facing SaaS. No authentication required. Tools like subfinder, amass, and Shodan/Censys queries surface the full domain footprint in minutes.
Conditions required:
  • Public-facing web assets discoverable via DNS/CT logs
Where this breaks in practice:
  • None — modern orgs have hundreds of public web hostnames
Detection/coverage: External attack surface management tools (Randori, RunZero, Bitsight) enumerate the same surface — use them defensively.
STEP 02

Harvest client-side artifacts

Attacker pulls HTML, all linked JavaScript bundles, and any .map sourcemap files. Tools: trufflehog filesystem, gitleaks, secretfinder.py, nuclei templates in exposures/tokens/, SecretScanner, and the same regex packs Tenable uses. Everything is scriptable and runs offline once assets are pulled.
Conditions required:
  • HTTP(S) reachability to the web asset
Where this breaks in practice:
  • Aggressive minification/obfuscation of bundles reduces regex hits
  • Bundlers that strip process.env at build time
Detection/coverage: WAF/CDN request-rate anomalies; unusual .map fetches; SecOps rarely alerts on these.
STEP 03

Extract secret and identify blast radius

Attacker finds a match — say AKIA... or sk_live_... or ghp_.... They fingerprint it: prefix identifies the vendor, and a one-shot API call (aws sts get-caller-identity, curl api.stripe.com/v1/charges, curl -H 'Authorization: token …' api.github.com/user) confirms validity and enumerates scope.
Conditions required:
  • A parseable, high-entropy secret is present in the fetched artifacts
Where this breaks in practice:
  • Secret is dead/rotated
  • Secret is a public/publishable key by design (Stripe pk_, Firebase web config, Segment write key)
Detection/coverage: Vendor-side telemetry: AWS CloudTrail GetCallerIdentity from unfamiliar IP, GitHub audit log for unfamiliar geographies, Stripe unusual API caller.
STEP 04

Pivot on the credential

If the secret grants access to a downstream identity/CI/cloud/PKI system, attacker uses standard offensive tooling: pacu or enumerate-iam for AWS; gitrob/octopoacher for GitHub PAT lateral movement; roadrecon for Azure AD tokens. This is where blast radius diverges — a workflow-scoped GitHub Actions token yields code; an AWS admin role yields the tenant.
Conditions required:
  • Secret has non-trivial scope
  • Downstream system is reachable from the internet
Where this breaks in practice:
  • Least-privilege IAM
  • Short-lived / rotated credentials
  • MFA/session binding on the underlying identity
Detection/coverage: GuardDuty UnauthorizedAccess:IAMUser/*, GitHub secret_scanning_alert, Okta impossible-travel, cloud-provider anomaly detection.
STEP 05

Achieve objective

Depending on scope: data exfil from S3/blob storage, source code theft, supply-chain poisoning via CI/CD credential, customer PII from Stripe/Twilio, or full tenant takeover. Median dwell time from a live AWS key to first data touch in reported incidents is under one hour.
Conditions required:
  • Credential authorizes the target action
Where this breaks in practice:
  • Data-egress monitoring, DLP, canary tokens in high-value buckets
Detection/coverage: Egress DLP, S3 bucket access anomaly, CloudTrail data events (if enabled — most orgs do not enable them).
03 · Intelligence Metadata

The supporting signals.

Signature typeTenable WAS plugin (not a CVE) — Data Exposure family, detection-only
Class / CWECWE-200 Exposure of Sensitive Information to an Unauthorized Actor
Vendor CVSSv3.0 8.6 High AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N · v4.0 8.7 High
In-the-wild statusNot a KEV-eligible finding (no CVE). Class-level exploitation is continuous and industrialized — see Truffle Security, GitGuardian State of Secrets Sprawl 2025 reporting >23M leaked secrets in public repos in 2024 alone.
PoC availabilityPublic tools: trufflehog, gitleaks, SecretFinder, nuclei exposures/tokens templates
EPSSN/A — no CVE; EPSS does not score detection signatures
KEVNot applicable
Exposure telemetryGitGuardian: ~1 in 10 developers exposed a secret in 2024. Shodan/Censys do not classify at this granularity but sourcemap exposure is trivially internet-wide.
Signature first published2023-12-11 · last updated 2025-10-21
ReportingTenable Research — internal detection engineering, not a coordinated disclosure
04 · The Call

noisgate verdict.

Final Verdict
= UNCHANGED to HIGH (7.5/10)

Assessed HIGH because the finding is trivially reachable by any unauthenticated internet user (View Source is the exploit) and the affected component class routinely embeds credentials with fleet- or tenant-scale blast radius. The single most decisive factor is the role multiplier: any single hit that turns out to be an AWS/GitHub/Okta/CI credential collapses the whole chain to CRITICAL, and Tenable will not tell you which kind you have — you must triage each match.

HIGH that the signature class is exploitable when it fires
MEDIUM that any given fire is a live, high-scope credential (false-positive rate is real)
HIGH that this class of finding drives real breaches (GitGuardian, Uber 2022, CircleCI 2023, Toyota 2022)

Why this verdict

  • Zero exploitation friction: unauthenticated, no CVSS PR, no user interaction, no exploit code. curl + grep is the full kill chain to step 3.
  • Role multiplier — worst plausible outcome dominates: if the leaked artifact is a cloud root key, GitHub PAT with repo, Okta admin API token, Stripe sk_live, or a code-signing / JWT signing key, the chain ends in tenant / supply-chain compromise. Per the noisgate deployment-role floor rule, that outcome is plausible for any organization running a modern web SPA with a CI/CD pipeline (≥10% of enterprise web builds have historically leaked *some* credential per GitGuardian) — floor is HIGH.
  • High false-positive plausibility keeps the floor from CRITICAL: many hits are publishable-by-design keys (Firebase web config, Stripe pk_, Segment writeKey, Sentry DSN, Google Maps client keys). These do not warrant emergency response.
  • Detection-signature status, not a patchable CVE: there is no version to bump — remediation is process (rotate + hunt the root cause), which makes SLA framing about *credential rotation deadlines*, not patch cycles.

Why not higher?

Not CRITICAL because a large fraction of real fires are publishable / low-scope keys (Stripe pk_, Firebase web config, analytics IDs). Blanket-treating every hit as CRITICAL burns the incident-response team on noise and desensitizes triage; the correct response is per-finding classification with a fast escalation path to CRITICAL for high-scope hits.

Why not lower?

Not MEDIUM because when the fire *is* a live cloud/CI/identity credential, the blast radius is fleet-scale and the exploitation cost is zero. Anchoring at MEDIUM would let a real Uber-2022-class exposure sit in a 365-day queue. The class has driven repeated public breaches — MEDIUM under-prices demonstrated real-world impact.

05 · Compensating Control

What to do — in priority order.

  1. Triage every hit within 24 hours and classify by secret type — Group findings into (a) publishable-by-design (Stripe pk_, Firebase web, Segment writeKey) → close as intended; (b) low-scope third-party keys → rotate at leisure; (c) high-scope (cloud, CI, identity, signing) → treat as active incident. Per noisgate mitigation SLA for HIGH: within 30 days for the class, but individual (c)-tier hits are effective-CRITICAL and get the ≤3-day / immediate track.
  2. Rotate the exposed secret before removing it from source — Order matters. If you delete the leaked value first and then rotate, attackers who already scraped it retain access. Issue a new credential, deploy the change, then invalidate the old value at the issuer (AWS IAM, GitHub, Okta, Stripe). Complete within the mitigation window.
  3. Enable secret scanning at every upstream stage — GitHub Advanced Security secret scanning + push protection, GitLab secret detection, pre-commit hooks with gitleaks, and CI-stage trufflehog on build artifacts. Deploy within 30 days per HIGH SLA — this is the only durable control that prevents recurrence.
  4. Kill sourcemap exposure in production — Configure webpack/Vite/Rollup to emit sourcemaps only for internal error-tracking upload (Sentry, Datadog) and NOT to /static/js/*.map on the public origin. Most WAS 114129 hits come from sourcemaps, not the bundle itself.
  5. Deploy canary tokens in high-value repos and cloud accounts — Plant Thinkst Canarytokens styled AWS keys, GitHub PATs, and Slack tokens in likely leak paths (.env.example, unused files, README examples). First alert on use = immediate triage signal that a real credential is out there too.
  6. Move to short-lived credentials wherever possible — OIDC-federated GitHub Actions to cloud (no static keys), IMDSv2-only EC2 roles, workload identity for K8s, aws sts assume-role with 15-minute TTLs. Removes the value of a leaked key even if one escapes. Roll out within the 180-day HIGH remediation window.
What doesn't work
  • WAF rules — the secret is IN the response body your server is intentionally sending; a WAF has no signal that says 'this string is a credential'.
  • Minification / obfuscation — regex/entropy scanners defeat minification trivially; obfuscation only slows a human, not trufflehog.
  • IP allowlisting the WAS scanner — you'll stop the *detection*, not the *disclosure*. Attackers scan too.
  • Rotating the secret without fixing the pipeline — the next build will re-embed it. Fix the root cause (env var management, build-time secret injection) or you'll see the same finding next quarter.
  • Password managers / vaults — irrelevant. The secret already left the vault the moment a developer pasted it into source.
06 · Verification

Crowdsourced verification payload.

Run this from an auditor workstation (or CI stage) with network reach to the target site. It fetches the HTML + linked JS bundles + sourcemaps and greps for common secret patterns — the same class of check Tenable WAS 114129 performs. Requires Python 3.9+ and requests. Invoke: python check_secret_disclosure.py https://app.example.com. No privileges required on the target.

noisgate-verify.py
PYTHONREAD-ONLYSAFE
#!/usr/bin/env python3
# noisgate — verify Tenable WAS 114129 (Generic Secret Disclosure) exposure
# Usage: python check_secret_disclosure.py <base_url>
# Exit: 0 PATCHED, 1 VULNERABLE, 2 UNKNOWN
import re, sys, urllib.parse as up
try:
    import requests
except ImportError:
    print('UNKNOWN: install requests (pip install requests)'); sys.exit(2)

if len(sys.argv) != 2:
    print('UNKNOWN: usage: check_secret_disclosure.py <base_url>'); sys.exit(2)

BASE = sys.argv[1].rstrip('/')
HEADERS = {'User-Agent': 'noisgate-secret-check/1.0'}
TIMEOUT = 15

# High-signal secret patterns. Extend as needed.
PATTERNS = {
    'AWS access key':          re.compile(r'AKIA[0-9A-Z]{16}'),
    'AWS secret key':          re.compile(r'(?i)aws(.{0,20})?[\'"][0-9a-zA-Z/+]{40}[\'"]'),
    'GitHub PAT (classic)':    re.compile(r'ghp_[0-9A-Za-z]{36}'),
    'GitHub fine-grained':     re.compile(r'github_pat_[0-9A-Za-z_]{82}'),
    'GitHub OAuth':            re.compile(r'gho_[0-9A-Za-z]{36}'),
    'Slack bot/user token':    re.compile(r'xox[baprs]-[0-9A-Za-z-]{10,}'),
    'Stripe live secret':      re.compile(r'sk_live_[0-9a-zA-Z]{24,}'),
    'Google API key':          re.compile(r'AIza[0-9A-Za-z_\-]{35}'),
    'Twilio SID':              re.compile(r'AC[0-9a-f]{32}'),
    'SendGrid API key':        re.compile(r'SG\.[0-9A-Za-z_\-]{22}\.[0-9A-Za-z_\-]{43}'),
    'PEM private key':         re.compile(r'-----BEGIN (RSA|EC|OPENSSH|DSA|PGP) PRIVATE KEY-----'),
    'JWT':                     re.compile(r'eyJ[A-Za-z0-9_\-]{10,}\.[A-Za-z0-9_\-]{10,}\.[A-Za-z0-9_\-]{10,}'),
    'Generic bearer secret':   re.compile(r'(?i)(secret|token|api[_-]?key|passwd|password)[\'"\s:=]{1,5}[\'"][A-Za-z0-9_\-]{24,}[\'"]'),
}

def fetch(url):
    try:
        r = requests.get(url, headers=HEADERS, timeout=TIMEOUT, allow_redirects=True)
        return r.text if r.status_code == 200 else ''
    except Exception:
        return ''

def scan(text, source):
    hits = []
    for name, pat in PATTERNS.items():
        for m in pat.findall(text)[:3]:
            snippet = m if isinstance(m, str) else str(m)
            hits.append((source, name, snippet[:80]))
    return hits

html = fetch(BASE)
if not html:
    print(f'UNKNOWN: could not fetch {BASE}'); sys.exit(2)

findings = scan(html, BASE)

# Extract linked JS + sourcemaps
js_urls = set(re.findall(r'<script[^>]+src=["\']([^"\']+\.js[^"\']*)', html, re.I))
for js in list(js_urls)[:25]:  # cap to keep runtime bounded
    full = up.urljoin(BASE + '/', js)
    body = fetch(full)
    findings += scan(body, full)
    m = re.search(r'//[#@]\s*sourceMappingURL=(\S+)', body)
    if m:
        smap = up.urljoin(full, m.group(1))
        findings += scan(fetch(smap), smap)

if findings:
    print('VULNERABLE: potential secret disclosure detected')
    for src, name, sample in findings[:20]:
        print(f'  [{name}] {src} :: {sample}')
    sys.exit(1)
print('PATCHED: no matching secret patterns in fetched surface')
sys.exit(0)
07 · Bottom Line

If you remember one thing.

TL;DR
Monday morning: run the verification script against every public web hostname and prioritize any hits by secret type. Per the noisgate mitigation SLA for HIGH, class-level compensating controls (secret scanning in CI, sourcemap suppression, per-finding triage playbook) must be in place within 30 days — but individual hits that turn out to be live cloud/CI/identity/signing credentials get the immediate / within-hours track because active-exploitation risk is continuous for that credential class. Per the noisgate remediation SLA, the durable fix (short-lived / federated credentials everywhere, developer training, pre-commit hooks) lands within 180 days. Rotate before deleting, hunt for prior use in cloud/CI/vendor audit logs, and treat any GitHub PAT / AWS root / Okta admin / code-signing key hit as an incident — not a finding.

Sources

  1. Tenable Plugin 114129 — Generic Secret Disclosure
  2. Tenable WAS Data Exposure plugin family
  3. CWE-200 — Exposure of Sensitive Information
  4. GitGuardian State of Secrets Sprawl 2025
  5. TruffleHog — secret scanner
  6. Gitleaks
  7. Nuclei exposures/tokens templates
  8. GitHub Secret Scanning + Push Protection
Peer Review

What defenders are saying.

Submit a review attribution: handle + country only
0 flags selected · stored anonymously
Validation Results

Crowdsourced verification outputs.

Results submitted by users who ran the verification payload against their environment.