Skip to content

VNX-341: Predictable from Observable State

Detects secrets built from state an attacker can observe or estimate (the clock, the process id, the client address or the host name), raw or hashed, when stored under, returned as or set as the cookie value of a secret. C, C++, Python, JavaScript/TypeScript, PHP, Java, Kotlin, Go and Ruby.

Updated 02 Nov 2026Checked against cli@de9b52a
Field Value
Rule ID VNX-341
Severity Medium
SARIF level warning
Kind sast
Languages C, C++, Python, JavaScript / TypeScript, PHP, Java, Kotlin, Go, Ruby
CWE CWE-341
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 randomness predictable cwe-341
Source internal/sast/rules/vnx-341.rego

Overview

VNX-341 maps to CWE-341: Predictable from Observable State. A token made from the time of the request, the PID of the server or the client’s IP address has only a handful of plausible values, and hashing it does not add any: an attacker computes the same hash for each candidate.

The rule reports the clock (time(), microtime(), date(), time.time(), datetime.now(), Date.now(), new Date(), getTime(), System.currentTimeMillis()/nanoTime(), Instant.now(), time.Now(), Time.now, clock(), tv_sec/tv_usec, hrtime, performance.now()), the process id (getpid(), os.getpid(), os.Getpid(), getmypid(), Process.pid, process.pid) and the client address or host name (REMOTE_ADDR, getRemoteAddr(), request.remote_addr, req.ip, remote_ip, RemoteAddr, gethostname(), uuid.getnode()) when the value is stored under, keyed by or returned as a secret (token, password, secret, nonce, salt, OTP, CSRF, session id, session cookie value, API key, reset/confirmation code), set as the value of a session or auth cookie, written with snprintf/strcpy into a buffer named for a secret, or assigned to a variable that reaches one of those within six lines.

What Gets Flagged

// FLAGGED: the session cookie is the clock
$cookie_value = time();
setcookie("dvwaSession", $cookie_value);
// FLAGGED: hashing the client address and the time adds nothing
$session_id = md5($_SERVER['REMOTE_ADDR'] . microtime());
# FLAGGED
token = hashlib.md5(str(time.time()).encode()).hexdigest()
session_id = f"{request.remote_addr}-{int(time.time())}"
// FLAGGED
const sessionId = Date.now().toString(36);

What Is Not Flagged

  • Timestamps stored as bookkeeping (iat, exp, expires, created, last_activity, login_time, token_expiry, ttl), cookie expiry arguments, and a timestamp used only with a lifetime added ($now + TOKEN_LIFE).
  • The error or status result of a call that takes the clock (err = signer.SignHTTP(..., time.Now())), and comparisons.
  • A line that also draws from a CSPRNG (random_bytes, secrets, os.urandom, crypto.randomBytes, SecureRandom, crypto/rand, RAND_bytes, getrandom, uuid4).
  • PRNG seeding (VNX-337), identifier generators such as uniqid() and time-based UUIDs (VNX-340), test files, and the pattern in comments or string literals.

Remediation

  1. Generate secrets with a CSPRNG and nothing else: secrets.token_urlsafe(), crypto.randomBytes(), random_bytes(), SecureRandom, crypto/rand, RAND_bytes().
  2. Keep timestamps for expiry checks, not for the secret itself.
  3. For confirmed false positives, add a # vulnetix-ignore: VNX-341 comment on the line.

References

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-341
// nosec vnx-341

Or record an ignore rule: vulnetix ignore add --rule vnx-341 --reason "...". See Suppressing findings.

Edit this pageSources: cli/internal/sast/rules/vnx-341.rego, cli/internal/sast/docs/vnx-341.md
esc
↑ ↓ move↵ openSearches in your browser. A key like autonomy.max or a code like threshold_required jumps straight to it.