Agent uses a static, long-lived credential

ID

agent-uses-static-long-lived-credential

Severity

high

Remediation Complexity

trivial

Remediation Risk

low

Remediation Effort

low

OWASP LLM

LLM02:2025 — Sensitive Information Disclosure

OWASP ASI

ASI03:2026 (Identity Abuse)

Family

LLM02 — Sensitive Information Disclosure

Red-team vectors

Credential Theft / NHI Abuse

Tags

ai_security

Description

An AI agent / tool manifest hardcodes a static, long-lived credential — an API key, a bearer token, or a connection string with an inline password — with no rotation or secret-manager reference. A non-expiring credential in a manifest is a pre-staged theft target: once read (repository access, a leaked log, a compromised peer agent) it grants standing access to the backing service until someone notices and rotates it by hand.

The detector is anchored on agent/tool manifests (a tools: / agents: / connection_ref signal is required) and obfuscates the matched secret before it enters the report. It is suppressed when the value is a reference/placeholder (${VAR}, env:, vault:, {{ …​ }}, <…​>) or the credential declares rotation metadata (credential_manager, ttl, rotation_policy, secretRef, valueFrom).

Rotation metadata is read per credential, not per file. It counts only when it is declared as a real key: value on the credential’s own block — the entry the credential belongs to, delimited by indentation, from its header line down to the first shallower line. Two consequences:

  • a neighbouring entry’s declaration does not vouch for this credential — a cache’s ttl: 300 is a cache lifetime, not a rotation policy for the API key of the tool below it;

  • prose does not either — a comment such as # no rotation policy, key never expires describes the vulnerability rather than managing the credential, and no longer clears the finding.

Examples

tools:
  - external-api:
      url: "https://api.example.com"
      auth: "Bearer sk-live-1234567890abcdef"   (1)
database:
  connection_string: "postgres://user:s3cr3t@prod.db:5432"   (1)
1 Hardcoded long-lived credential in an agent manifest — flagged.

A value from a secret manager produces no finding:

tools:
  - external-api:
      auth: "${API_TOKEN}"          # reference, not a literal
      rotation_policy: "30d"        # rotation metadata on this credential's own block

A declaration on a different entry does not reach it, and is flagged:

tools:
  - name: cache
    ttl: 300                                  # the cache's lifetime, not a rotation policy
  - name: metrics-api
    api_key: "sk-live-1234567890abcdef"       (1)
1 Hardcoded credential on an entry that declares no rotation metadata of its own — flagged.

Mitigation / Fix

  • Move the credential to a secret manager / vault and reference it (env var, secretRef, valueFrom).

  • Attach a TTL / rotation policy; prefer short-lived, automatically rotated credentials.

  • Never commit the literal credential to a manifest.

© 2026 Xygeni. All rights reserved