← Back to Feed CACHED · 2026-05-17 09:42:19 · cache_key CVE-2025-29912
tenable:121039 · CWE-862 · Disclosed 2019-01-09

Missing Function Level Access Control

ASSESSED — NOISGATE V0.5
Vendor
Reassessed
Verdict:
01 · The Real Story

This is finding a locked door in the UI, then checking whether the same room is still open through the side entrance

Tenable plugin 121039 is a generic web-application authorization test, not a product-specific CVE. It looks for cases where a remote web app exposes privileged functionality to a low-privileged or even unauthenticated user because the server fails to enforce authorization on the function itself. Tenable published this plugin on 2019-01-09 and currently scores it as Critical / CVSS 9.1; the scan only runs when generic web application tests are enabled, and the plugin documentation shows it depends on web-app test settings rather than any affected software version range.

The vendor score is too aggressive for patch prioritization at enterprise scale. Broken access control is absolutely dangerous when confirmed, but this plugin is a category-level DAST signal with heavy real-world friction: it often requires hidden endpoint discovery, role-context testing, and manual confirmation that a privileged action actually succeeded. In other words, the bug class is severe; the *scanner finding* is not automatically a Critical patch event.

"Real bug class, but this Tenable hit is a generic web finding that usually needs manual validation before you burn patch capital."
02 · The Attack Path

4 steps from start to impact.

STEP 01

Map privileged endpoints with Burp Suite Spider or ffuf

The attacker first discovers admin or role-restricted routes by crawling, force-browsing, or observing client-side links and JavaScript. Common targets are /admin, /api/admin/*, workflow actions, export functions, and hidden POST endpoints. This step is routine in web testing, but it is still application-specific and not guaranteed to produce anything useful.
Conditions required:
  • Reachable web application endpoint
  • Ability to browse or crawl the application
  • Sufficient route predictability or discoverability
Where this breaks in practice:
  • Modern SPAs can hide routes behind client state and API choreography
  • Unlinked endpoints may not be guessable
  • Rate limiting, WAFs, and bot controls often slow enumeration
Detection/coverage: DAST can suggest candidates, but coverage is incomplete; crawlers routinely miss role-specific or JavaScript-driven paths.
STEP 02

Obtain a low-priv session using normal app registration or credentials

Most exploitable cases are authenticated horizontal or vertical authorization failures, so the attacker typically needs a valid low-privilege account. Tools like Burp Repeater or OWASP ZAP replay requests from that weaker session against privileged functions. If the issue is truly unauthenticated, severity rises fast, but that is not the default assumption for this plugin.
Conditions required:
  • Valid session token, cookie, or API key for a lesser role, or an unauthenticated route if exposed
  • Ability to preserve and replay HTTP requests
Where this breaks in practice:
  • Registration may be closed or approval-gated
  • MFA, anti-automation, and device binding can limit session acquisition
  • Role separation may be sparse in non-admin workflows
Detection/coverage: Authenticated scanning helps, but many scanners cannot reliably exercise every role combination or business workflow.
STEP 03

Replay the privileged function directly with Burp Repeater or curl

The attacker sends the privileged request directly, bypassing the UI and any client-side restrictions. If the server only hid the button rather than enforcing authorization, the call succeeds despite the lower role. OWASP explicitly treats this as broken access control / authorization bypass.
Conditions required:
  • Known privileged endpoint and parameters
  • Server-side authorization missing or inconsistently applied
Where this breaks in practice:
  • Many apps do block with 401/403 once the direct request is replayed
  • CSRF tokens, nonce values, and workflow state can break simple request replay
  • Some findings are read-only or cosmetic rather than impactful
Detection/coverage: Manual validation is the gold standard. A 2xx alone is insufficient; you need proof the privileged function actually executed.
STEP 04

Convert access into impact with app-native actions

Successful exploitation can expose data, perform admin actions, alter workflow state, or pivot into account takeover depending on the function reached. The blast radius is therefore entirely tied to the specific endpoint: viewing another user's profile is not equivalent to creating admins, exporting PII, or changing billing settings.
Conditions required:
  • Privileged function performs a meaningful action
  • Application trusts the caller once the route is reached
Where this breaks in practice:
  • Impact may be limited to a single object, tenant, or workflow step
  • Many findings do not grant code execution or infrastructure compromise
  • Tenant isolation or secondary approval steps can cap damage
Detection/coverage: App logs, API gateway logs, and business-event monitoring can sometimes reveal unauthorized admin actions, but generic infrastructure scanners usually cannot confirm business impact.
03 · Intelligence Metadata

The supporting signals.

In-the-wild statusNo CVE is tied to this plugin, so there is no KEV entry and no product-specific in-the-wild evidence to anchor on. Treat it as an application-specific logic finding, not a mass-exploitation signature.
Proof-of-concept availabilityGeneric tradecraft is widely available via Burp Suite Repeater, OWASP ZAP, and public access-control testing guidance from PortSwigger and OWASP WSTG.
EPSSN/A — EPSS is CVE-based, and this Tenable plugin is a generic vulnerability class finding rather than a CVE record.
KEV statusNot applicableno CVE, therefore no CISA Known Exploited Vulnerabilities catalog entry or KEV listing date.
CVSS vectorTenable assigns CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N = 9.1. That vector assumes a clean network-path exploit with no role or workflow friction, which is often too optimistic for real deployments.
Affected versionsNo vendor product/version range is defined. The finding applies to any web application route where privileged functionality is reachable without correct server-side authorization.
Fixed versionsNone published. Remediation is code/config based: enforce authorization checks on the server for every privileged function and role boundary.
Scanning and exposure realityInternet search engines like Shodan/Censys cannot reliably fingerprint this flaw class. Exposure only exists where a specific application publishes reachable privileged functionality and the server-side authorization check is missing.
Disclosure dateTenable plugin published 2019-01-09; current plugin page shows it updated 2026-03-23.
Research lineageThis is aligned with OWASP A01 Broken Access Control and MITRE CWE-862 Missing Authorization, not a named researcher-disclosed product bug.
04 · The Call

noisgate verdict.

Final Verdict
DOWNGRADED to MEDIUM (6.1/10)

The decisive downgrade factor is attack-path friction: most real exploits here require endpoint discovery plus a low-privileged or contextual session, which makes this a post-enumeration application-logic issue rather than a turnkey internet-scale compromise. The impact can be severe once validated, but the reachable population and exploit reliability are too uncertain to treat every hit as Critical.

HIGH This is a generic DAST-style authorization finding rather than a product-specific CVE
MEDIUM Severity downgrade from Tenable's baseline based on real-world exploit friction
LOW Exact business impact without the plugin output and affected route details

Why this verdict

  • Vendor baseline is inflated for patch ops: Tenable's 9.1 assumes PR:N/UI:N, but real exploitation commonly requires route discovery, a valid low-priv session, or a role boundary to abuse.
  • Reachable population is narrow: this is only exploitable on the specific application paths where authorization is missing; it is not a fleet-wide software defect with a universal exploit.
  • Modern controls add friction: authenticated scanning gaps, MFA, anti-automation, WAFs, CSRF/workflow state, and tenant segmentation frequently break the clean exploit path implied by CVSS.

Why not higher?

I am not calling this HIGH or CRITICAL because the finding is not a vendor-confirmed product vulnerability with known affected versions, known exploit code, or broad exploitation telemetry. In many environments it is a candidate logic flaw that still needs a human to prove an actual unauthorized action succeeded and to measure blast radius.

Why not lower?

I am not pushing this to LOW because broken access control remains one of the most damaging web-app classes when validated. If the privileged function exposes sensitive data, admin actions, or cross-tenant impact, the practical business risk is real even without a CVE.

05 · Compensating Control

What to do — in priority order.

  1. Validate the route manually — Use an auditor workstation with Burp Suite, OWASP ZAP, or curl to confirm whether the exact endpoint found by Tenable returns a meaningful privileged action to an unauthenticated or low-privileged session. Because this is a MEDIUM verdict, there is no mitigation SLA; validate before mobilizing engineering, then place confirmed issues into the remediation queue within 365 days unless business impact justifies faster handling.
  2. Enforce server-side authorization centrally — Move authorization checks into middleware, route guards, controller decorators, or policy engines rather than relying on hidden UI elements or client-side role checks. For confirmed findings, ship that control as the durable fix within the 365-day remediation window for MEDIUM, sooner if the route is internet-facing and touches admin or regulated data.
  3. Constrain sensitive endpoints at the edge — Where practical, put admin routes behind SSO groups, VPN, IP allowlists, or API gateway policy so the reachable population shrinks even if application logic is imperfect. This is a useful compensating control while the application team works the code fix inside the 365-day remediation window.
  4. Log authorization failures and privileged actions — Instrument the app and gateway to record 401/403, role mismatches, admin route access, export actions, and state-changing privileged API calls. Detection does not fix the bug, but it reduces dwell time and gives you evidence if a confirmed finding is probed before code remediation lands.
What doesn't work
  • Hiding admin links in the UI or client-side JavaScript does not help; direct requests to the endpoint still work if the server never checks authorization.
  • TLS, secure cookies, and WAF signatures do not solve missing authorization logic; they protect transport and some attack patterns, not business-rule enforcement.
  • MFA alone does not fix this class when the attacker can authenticate as a normal user and then replay a forbidden function.
06 · Verification

Crowdsourced verification payload.

Run this from an auditor workstation against the affected application after you identify the suspected privileged route from the Tenable output. Invoke it as python verify_mflac.py https://app.example.com /admin/users --cookie "session=LOWPRIVCOOKIE" --allow-text "User Administration"; no local admin rights are needed, but you do need a known low-priv session if the route is authenticated.

noisgate-verify.py
PYTHONREAD-ONLYSAFE
#!/usr/bin/env python3
# verify_mflac.py
# Purpose: sanity-check a suspected Missing Function Level Access Control finding.
# Output: VULNERABLE / PATCHED / UNKNOWN
# Exit codes: 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN, 3=usage/network error

import argparse
import sys
import requests
from urllib.parse import urljoin

DENY_CODES = {401, 403}
REDIRECT_DENY_HINTS = ('login', 'signin', 'auth')


def build_session(cookie_header: str, header_list):
    s = requests.Session()
    if cookie_header:
        s.headers['Cookie'] = cookie_header
    for item in header_list:
        if ':' not in item:
            continue
        k, v = item.split(':', 1)
        s.headers[k.strip()] = v.strip()
    s.headers.setdefault('User-Agent', 'noisgate-mflac-check/1.0')
    return s


def is_redirect_to_login(resp):
    if not resp.history and resp.status_code not in (301, 302, 303, 307, 308):
        return False
    loc = resp.url.lower()
    return any(hint in loc for hint in REDIRECT_DENY_HINTS)


def main():
    parser = argparse.ArgumentParser(description='Verify suspected Missing Function Level Access Control')
    parser.add_argument('base_url', help='Base URL, e.g. https://app.example.com')
    parser.add_argument('path', help='Suspected privileged path, e.g. /admin/users')
    parser.add_argument('--cookie', default='', help='Cookie header for low-priv session, e.g. "session=abc"')
    parser.add_argument('--header', action='append', default=[], help='Additional header, repeatable, e.g. "X-CSRF-Token: abc"')
    parser.add_argument('--method', default='GET', choices=['GET', 'POST', 'HEAD'], help='HTTP method to use')
    parser.add_argument('--data', default='', help='Optional POST body')
    parser.add_argument('--allow-text', default='', help='Text that indicates the privileged page/action really loaded')
    parser.add_argument('--timeout', type=int, default=15, help='HTTP timeout in seconds')
    args = parser.parse_args()

    url = urljoin(args.base_url.rstrip('/') + '/', args.path.lstrip('/'))
    session = build_session(args.cookie, args.header)

    try:
        if args.method == 'GET':
            resp = session.get(url, timeout=args.timeout, allow_redirects=True, verify=True)
        elif args.method == 'HEAD':
            resp = session.head(url, timeout=args.timeout, allow_redirects=True, verify=True)
        else:
            resp = session.post(url, data=args.data, timeout=args.timeout, allow_redirects=True, verify=True)
    except requests.RequestException as exc:
        print(f'UNKNOWN - request failed: {exc}')
        sys.exit(3)

    body = resp.text[:200000] if hasattr(resp, 'text') else ''

    if resp.status_code in DENY_CODES or is_redirect_to_login(resp):
        print(f'PATCHED - access denied ({resp.status_code}) for {url}')
        sys.exit(0)

    if 200 <= resp.status_code < 300:
        if args.allow_text:
            if args.allow_text.lower() in body.lower():
                print(f'VULNERABLE - privileged content marker matched on {url} ({resp.status_code})')
                sys.exit(1)
            else:
                print(f'UNKNOWN - got {resp.status_code} but privileged content marker not found on {url}')
                sys.exit(2)
        else:
            print(f'UNKNOWN - got {resp.status_code} on {url}; provide --allow-text to confirm real privileged access')
            sys.exit(2)

    if resp.status_code in (301, 302, 303, 307, 308):
        print(f'UNKNOWN - redirect observed ({resp.status_code}) to {resp.url}')
        sys.exit(2)

    print(f'UNKNOWN - unexpected status {resp.status_code} for {url}')
    sys.exit(2)


if __name__ == '__main__':
    main()
07 · Bottom Line

If you remember one thing.

TL;DR
Monday morning, treat this as an application triage item, not a fleetwide emergency patch. Pull the Tenable plugin output, manually validate the exact route and role context, and only then open engineering work for confirmed cases; because this is MEDIUM, there is no noisgate mitigation SLA — go straight to the 365-day remediation window for the durable code fix, but if you validate internet-facing admin or sensitive-data exposure, add an immediate temporary edge restriction while the permanent fix is scheduled under the noisgate remediation SLA of ≤365 days.

Sources

  1. Tenable Plugin 121039
  2. Tenable Nessus Web Application Scanning
  3. Tenable Nessus User Guide PDF - Generic web application tests
  4. OWASP Top 10 A01 Broken Access Control
  5. OWASP WSTG - Testing for Bypassing Authorization Schema
  6. MITRE CWE-862 Missing Authorization
  7. PortSwigger Web Security Academy - Access control vulnerabilities
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.