AI004 · STOA-LLM06-SENSITIVE-INTERPOLATION
Identifier suggesting sensitive data observed interpolated into an external model call.
- OWASP: LLM06 Sensitive Information Disclosure (v1.1); LLM02 (2025).
- Severity: high (secret class) / medium (PII class). Gates: no.
- Kind: data-flow (needs the AST layer).
Detection
A taint chain from a sensitive source into a prompt sink where the model call targets an external provider:
- Secret class (high):
os.environ["..._KEY"],getenv,process.env.*
matching the credential lexicon; .api_key/.secret/.token/.password reads. SEC001 placeholder/entropy checks are reused to avoid flagging API_KEY = "your-key-here" flows.
- PII class (medium): identifier reads matching the PII lexicon
(email, phone, ssn, dob, address, salary, diagnosis, passport, iban, card_number, national_id, …), extendable via [rules.AI004].pii_terms.
Local endpoints (Ollama, localhost) downgrade severity one tier and tag local_endpoint_observed. Credentials used only in auth headers (not the prompt) are not flagged.
Vulnerable → remediated
# VULNERABLE — PII embedded in a prompt to an external provider
prompt = f"Write a reminder to {user.email}, SSN {user.ssn}, owing ${user.balance}."
openai.chat.completions.create(model="gpt-4.1", messages=[{"role": "user", "content": prompt}])
# REMEDIATED — pseudonymize; rejoin identifiers outside the model call
prompt = f"Write a reminder for a customer who owes ${user.balance}."
Finding message
An identifier suggesting {a credential / personal data} is interpolated into a prompt passed to a model call. Identifier names suggest — but do not prove — sensitive data (OWASP LLM06). Values are never read or transmitted by Stoa; this finding is based on identifier names and flow shape only.
Suppress: # stoa: ignore[AI004] reason