AI API key not managed

warningai-api-key-unmanaged

This AI vendor is reached with an API key, and nothing in the design holds or rotates that key. It ends up in environment files or code, every caller shares it, and a single leak runs up the vendor bill until someone notices. Put the key in a key-management component, or say it is held there with keyStore.

Severity
warning
Selects
every node of kind ai-service
Components in scope
126
What it checks

It looks at every node of kind ai-service, and fires when:

  • — all of these hold:
  • — the node's `auth` is "api-key"
  • — the node's `keyStore` is false
  • — the node has at least one incoming edge from an app-server, worker or client
  • — this does not hold:
  • — the design contains a node of kind key-management
Message
AI service '{{node.id}}' is called with an API key, the key is not held in a key-management component, and the design has none.

{{node.id}} style paths are filled in from the node, the edge or the design the finding is about.

Applies to · 126 components
Tripped by · 2

Reference designs whose broken twin names this rule in its header. The gate reads the same header, and fails when a rule no design trips.

Source
# yaml-language-server: $schema=../schema/rule.schema.json
# An AI vendor reached with an API key, called from the team's own servers, workers or clients,
# with the key not declared as held in a key-management component and no key-management node in
# the design. The key then lives in configuration or code, unrotated, and one leak bills the account.
# Tripped by: designs/reference/llm-gateway/design.broken.yaml and designs/reference/linear-sync/design.broken.yaml
schemaVersion: "1"
type: "rule"
id: "ai-api-key-unmanaged"
severity: "warning"
select:
  node:
    kind: "ai-service"
when:
  all:
    - prop: "auth"
      equals: "api-key"
    - prop: "keyStore"
      equals: false
    - hasEdge:
        direction: "in"
        peerKind: ["app-server", "worker", "client"]
    - not:
        hasNode:
          kind: "key-management"
message: "AI service '{{node.id}}' is called with an API key, the key is not held in a key-management component, and the design has none."

The same page as markdown, for an agent: /catalogue/rules/ai-api-key-unmanaged.md