VNX-213: Exposure of Sensitive Information Due to Incompatible Policies
Detects health, status and debug endpoints that return the whole process environment or application configuration (process.env, os.environ, app.config, os.Environ(), System.getenv()), publishing every secret an operator put there.
| Field | Value |
|---|---|
| Rule ID | VNX-213 |
| Severity | Medium |
| SARIF level | warning |
| Kind | sast |
| Languages | Go, Java, JavaScript / TypeScript, Python |
| CWE | CWE-213 |
| CAPEC | CAPEC-66 |
| ATT&CK | T1190 |
| CWSS vector | CWSS:1.0/TI:M/AP:RU/AL:S/IC:N/FC:LT/RP:RU/RL:S/AV:L/AS:N/IN:A/SC:A/BI:M/DI:H/EX:M/EC:N/P:C |
| Tags | policy exposure environment configuration cwe-213 |
| Source | internal/sast/rules/vnx-213.rego |
Overview
VNX-213 maps to CWE-213: Exposure of Sensitive Information Due to Incompatible Policies. The weakness is a conflict between two policies: the developer’s (“this endpoint shows runtime facts”) and the operator’s (“secrets go in environment variables and config”). No line of code shows a policy, so the rule reports the most concrete place the conflict appears: an endpoint that returns the whole environment or configuration, which is where operators put database passwords, API keys and signing secrets.
| Language | Reported |
|---|---|
| JavaScript, TypeScript | process.env passed whole (alone, in an object, spread, or JSON.stringify(process.env)) to res.send/json/end/write/render, ctx.body or reply.send, directly or through a variable |
| Python | dict(os.environ), os.environ.copy()/.items(), app.config (whole or .items()), settings.__dict__, vars(settings) inside jsonify, JsonResponse, HttpResponse, make_response, Response, render_template |
| Go | os.Environ() encoded or written to the http.ResponseWriter or a gin context, including a range os.Environ() loop that writes each entry |
| Java | System.getenv() / System.getProperties() (no argument) returned from a controller or servlet, or put in ResponseEntity, a body, a model attribute or the response writer |
What Gets Flagged
app.get('/healthz', (req, res) => {
res.json({ status: 'ok', env: process.env }); // FLAGGED
});
return jsonify(status="ok", environment=dict(os.environ)) # FLAGGED
@router.get("/debug/env")
def env_dump():
return dict(os.environ) # FLAGGED
json.NewEncoder(w).Encode(os.Environ()) // FLAGGED
What Is Not Flagged
- Single variables:
process.env.APP_VERSION,os.environ.get("X"),System.getenv("X"). Object.keys(process.env)(names only), and environments copied for a subprocess (env=os.environ.copy(),cmd.Env = os.Environ()).- Spring Actuator exposure (VNX-JAVA-002) and
phpinfo()(VNX-PHP-008), which have their own rules. - An environment returned from a function no route exposes (a settings loader), or filtered before it is written (
if strings.HasPrefix(kv, "PUBLIC_")). - Comments, string literals and test code.
Remediation
Return an explicit allow-list of fields.
res.json({ status: 'ok', version: process.env.APP_VERSION });
References
- CWE-213: Exposure of Sensitive Information Due to Incompatible Policies
- CWE-526: Cleartext Storage of Sensitive Information in an Environment Variable
Suppressing this rule
Put a nosec comment on the line, or on line 1 to cover the whole file. Use the comment marker of the file’s language (#, //, -- or ;):
# nosec vnx-213
// nosec vnx-213
Or record an ignore rule: vulnetix ignore add --rule vnx-213 --reason "...". See Suppressing findings.