CoreLayer AI Security Platform logoCoreLayer AI Security Platform

Fingerprint Runtime Agent

An observe-only gateway that sits between your application and an OpenAI-compatible endpoint. It builds a behavioural baseline, scores every exchange against it, enforces capability policy, and reports security telemetry to the CoreLayer control plane without touching model responses.

The corelayer-fingerprint-agent is a separate binary from the secureai CLI. It runs as a long-lived service rather than a one-shot command, and it is designed to sit on the inference path permanently. Your application sends its existing POST /v1/chat/completions requests to the agent instead of directly to the provider. The agent forwards each request to one fixed upstream, streams or returns the upstream response unchanged, and performs all scoring and telemetry work off the response path.

Nothing is blocked or rewritten

The agent does not block, rewrite, redact, retry, or choose model responses. If the agent process goes down or falls behind, the customer application loses observability, never inference. Policy detections and anomaly scores are telemetry, not authorization decisions.

How the agent works

On every request the agent performs the same sequence, entirely off the response path:

  1. Proxy. Forward the request to the fixed upstream and stream the response back to the caller, byte for byte. Header credentials pass through. The agent adds nothing to the response.
  2. Extract. Parse the request and response bodies (both streaming and non-streaming) into a structured inference record: model, messages, tool declarations, tool calls, token counts.
  3. Sessionize. Group the exchange into a pseudonymous session using X-CoreLayer-Session-ID, the OpenAI user field, or a privacy-preserving connection fingerprint. Session IDs are HMAC-derived per process and never stored in cleartext.
  4. Calibrate. During the calibration window the agent collects clean samples to build a behavioural baseline. Once the minimum sample count and duration are met, calibration activates and scoring begins.
  5. Score. Run the LBF (behavioural fingerprinting) engine against the session history. If the anomaly score crosses the alert threshold, emit a behavior_anomaly event.
  6. Evaluate policy. Check request ceilings (tokens, message count, request size), tool authorization, capability boundaries (CBE), context access control (LCAC), and dangerous tool-call sequences. Every detection is observe-only.
  7. Spool and upload. Write the score sample and any events to an encrypted, crash-safe disk spool. A background worker delivers batches to the control plane with exponential backoff and idempotent retries.

Before you install

Installation is driven from the CoreLayer dashboard. Open the Runtime section, select the model you want to observe, and generate an installation revision. The dashboard produces:

  • An agent.yaml configuration file containing the non-secret identifiers, upstream URL, policy, and LCAC rules for this revision.
  • A one-time enrollment token. This token is short-lived and single-use. The agent exchanges it for a runtime credential on first startup, then the token is no longer needed.

Changing the content-capture setting or the policy creates a new immutable revision. Install that revision and let it enroll before retiring the previous one.

Docker Compose

The published container image runs as UID 65532 with every Linux capability dropped, a read-only root filesystem, bounded CPU and memory, and an HTTP health check. One persistent named volume holds the credential, calibration state, and encrypted spool.

Terminal
cd deploy/fingerprint-agent
cp ../../secureai.agent.example.yaml agent.yaml
cp agent.env.example agent.env
chmod 0644 agent.yaml
chmod 0600 agent.env

# Paste the dashboard enrollment token into agent.env, then:
docker compose up -d
docker compose ps
curl -fsS http://127.0.0.1:8090/readyz

The published port binds to 127.0.0.1 by default. A sibling Compose service can reach the gateway at http://fingerprint-agent:8090/v1/chat/completions on the project network. Set CORELAYER_AGENT_BIND_IP only when another host must reach the gateway, and protect port 8090 with a firewall or private load balancer.

After the dashboard confirms enrollment, blank the token in agent.env and recreate the container. The runtime credential is stored in the named volume.

Terminal
printf 'CORELAYER_AGENT_ENROLLMENT_TOKEN=\n' > agent.env
chmod 600 agent.env
docker compose up -d --force-recreate

Linux binary and systemd

The install script downloads the versioned archive for your architecture, verifies it against the SHA-256 manifest, installs the binary to /usr/local/bin, and enables a hardened systemd unit. It runs as a locked corelayer-agent user with only the data directory writable.

Terminal
curl -fsSLo /tmp/install-corelayer-agent.sh \
  https://get.corelayersecurity.com/agent/install.sh
less /tmp/install-corelayer-agent.sh

# Save the dashboard token without putting it in a shell argument.
umask 077
read -r -s CORELAYER_AGENT_ENROLLMENT_TOKEN
printf '%s' "$CORELAYER_AGENT_ENROLLMENT_TOKEN" > /tmp/corelayer.token
unset CORELAYER_AGENT_ENROLLMENT_TOKEN

sudo CORELAYER_AGENT_CONFIG_FILE=/path/to/dashboard-agent.yaml \
  CORELAYER_AGENT_ENROLLMENT_TOKEN_FILE=/tmp/corelayer.token \
  sh /tmp/install-corelayer-agent.sh
rm -f /tmp/corelayer.token

If no dashboard config is provided, the installer writes a safe placeholder and leaves the service stopped. Edit /etc/corelayer/agent.yaml, then start it manually.

Terminal
sudo systemctl status corelayer-fingerprint-agent
curl -fsS http://127.0.0.1:8090/healthz
curl -fsS http://127.0.0.1:8090/readyz
journalctl -u corelayer-fingerprint-agent --since "10 minutes ago"

Once enrollment completes, remove the token assignment from /etc/corelayer/fingerprint-agent.env and restart. To pin a specific release or install without the service:

Terminal
CORELAYER_AGENT_VERSION=0.1.0 \
CORELAYER_AGENT_INSTALL_DIR="$HOME/bin" \
CORELAYER_AGENT_SKIP_SERVICE=1 \
  sh /tmp/install-corelayer-agent.sh

Kubernetes and Helm

The Helm chart defaults to one replica because the local baseline, credential, and spool have a single writer. It enables a persistent volume, a read-only root filesystem, non-root UID/GID, dropped capabilities, seccomp RuntimeDefault, resource limits, probes, and checksum-triggered rollout on configuration changes.

Create the enrollment Secret out of band so it never enters a values file or Helm release history:

Terminal
kubectl create namespace corelayer
kubectl -n corelayer create secret generic corelayer-agent-enrollment \
  --from-literal=enrollment-token="$CORELAYER_AGENT_ENROLLMENT_TOKEN"

helm upgrade --install fingerprint-agent \
  ./deploy/fingerprint-agent/helm/corelayer-fingerprint-agent \
  --namespace corelayer \
  --set enrollment.existingSecret=corelayer-agent-enrollment \
  --set image.tag=0.1.0

The in-cluster gateway address is:

Endpoint
http://fingerprint-agent-corelayer-fingerprint-agent.corelayer.svc:8090/v1/chat/completions

After the dashboard shows a successful enrollment, upgrade the Deployment to remove its Secret reference, then delete the one-time Secret:

Terminal
helm upgrade fingerprint-agent \
  ./deploy/fingerprint-agent/helm/corelayer-fingerprint-agent \
  --namespace corelayer --reuse-values \
  --set enrollment.existingSecret=""
kubectl -n corelayer delete secret corelayer-agent-enrollment

NetworkPolicy

networkPolicy.enabled is off by default because standard Kubernetes NetworkPolicy cannot express upstream and control-plane DNS names. When enabled, the included policy allows gateway ingress plus DNS and HTTPS egress. Narrow it with selectors or your CNI's FQDN rules. serviceMonitor.enabled renders a Prometheus Operator ServiceMonitor for /metrics.

Configuration reference

The agent reads a single strict YAML file at startup. Group-writable or world-writable files are rejected. The config is immutable after startup: capture_content cannot be changed by the control plane or any HTTP endpoint.

Top-level fields

FieldDefaultDescription
versionrequiredMust be 1.
listen127.0.0.1:8090Address the gateway binds to.
agent_idrequiredDashboard-generated agent identifier.
model_idrequiredDashboard-generated model identifier.
revision_idrequiredDashboard-generated revision identifier.
capture_contentfalseWhen true, redacted prompt and response snippets are included in anomaly and detection events. Changing this creates a new dashboard revision.

upstream

FieldDefaultDescription
urlrequiredFixed OpenAI-compatible Chat Completions endpoint.
modelempty (any)Expected provider model name (e.g. gpt-4o). A differing request model is reported as inventory drift. This is not the model_id above.
timeout10mUpstream request timeout.
max_request_bytes8388608Hard request body ceiling. Requests above this fail.
max_observation_bytes8388608How much of a response is held for analysis.
observation_queue256Bounded queue between the response path and the processor.

control_plane

FieldDefaultDescription
urlrequiredControl plane origin, no path.
enrollment_token_envemptyEnvironment variable holding the one-time enrollment token. The token is never read from the YAML file itself.
credential_filerequiredWhere the runtime credential is stored after enrollment.
request_timeout15sTimeout for individual control-plane requests.
heartbeat_interval30sHow often a content-free heartbeat is sent.

calibration

Calibration builds the behavioural baseline from clean traffic. The agent does not alert during calibration. Once both min_samples and min_duration are met, calibration activates and scoring begins.

FieldDefaultDescription
state_filerequiredWhere calibration state is persisted.
min_samplesrequiredMinimum clean exchanges before activation (at least 2).
max_samplesrequiredMaximum samples retained in the baseline.
min_durationrequiredMinimum wall-clock time before activation.
alert_threshold0.75Anomaly score in (0, 1] above which a session is flagged.
reset_on_extractor_changefalseWhen false, an extractor upgrade marks the baseline stale until an administrator installs a new revision or resets calibration.

Build the baseline from clean traffic

Calibrating over a period that already contains an ongoing attack teaches the model that the attack is normal. Anomaly scores will look reassuring while nothing is being caught.

sessions

FieldDefaultDescription
ttlrequiredHow long an idle session lives in memory.
max_sessionsrequiredLRU ceiling on concurrent sessions.
max_turnsrequiredPer-session turn bound. Older turns are dropped.

spool

The encrypted disk spool buffers telemetry locally when the control plane is unreachable. The spool is bounded: when full, the oldest items are evicted so new telemetry can be written. An AES-256 key is auto-generated alongside the queue directory on first startup.

FieldDefaultDescription
directoryrequiredWhere spool files are written.
encryption_key_fileautoAES-256 key path. Defaults to a sibling of the spool directory.
max_bytesrequiredTotal spool size ceiling in bytes.
max_itemsrequiredMaximum queued items.
batch_size100Items per upload batch (max 200).
flush_interval5sHow often the uploader checks for queued items.
min_backoff1sInitial retry delay after an upload failure.
max_backoff1mMaximum retry delay.

policy

All policy checks are observe-only. Exceeding a limit or using an unlisted capability creates a detection but never blocks or modifies model traffic.

FieldDescription
allowed_toolsAllowlist of tool names the model may invoke. Use [] to deny all tools.
tool_kindsMaps each allowed tool name to read, write, delete, admin, or external.
allowed_capabilitiesWhich tool kinds are permitted for this agent.
dangerous_sequencesOrdered tool-kind chains that create a detection. For example, ["read", "external"] flags a read followed by an external call.
degradation_thresholdAnomaly score at which CBE switches the session to observe-only degradation.

policy.limits

FieldDescription
max_request_bytesObserve-only request size ceiling.
max_messagesMaximum messages in a single request.
max_input_tokensEstimated input token ceiling.
max_output_tokensOutput token ceiling.
max_total_tokensCombined token ceiling per turn.
max_tool_callsSession-wide tool call ceiling.
max_api_callsSession-wide external API call ceiling.
max_file_opsSession-wide file operation ceiling.

lcac

The LCAC (context access control) engine evaluates assembled prompt context against a Policy-as-YAML ruleset. In the agent, a deny is a detection, never a blocked request.

FieldDefaultDescription
enabledtrueSet to false to disable the LCAC engine entirely.
identity_headersSee belowMaps attribute names to HTTP headers. Defaults to X-CoreLayer-Tenant-ID and X-CoreLayer-Role.
namespace_headerX-CoreLayer-NamespaceHeader carrying the data namespace for context scoping.
time_headerX-CoreLayer-Request-TimeHeader carrying the local request time for time-of-day conditions.
policydefaultInline LCAC policy. Covers identity, context, actions, conditions, and data flow rules.

Gateway endpoints

PathMethodPurpose
/v1/chat/completionsPOSTTransparent proxy. Your application sends its normal OpenAI requests here.
/healthzGETLiveness. Returns the agent ID, model ID, and extractor version.
/readyzGETReadiness. Returns 503 until background workers have started.
/metricsGETPrometheus exposition format. All counters and gauges listed below.

Prometheus metrics

The /metrics endpoint serves Prometheus exposition format with no external dependencies. Point your scrape config at port 8090.

MetricTypeDescription
corelayer_fingerprint_readygauge1 when the gateway is accepting traffic.
corelayer_fingerprint_requests_totalcounterChat completion requests received.
corelayer_fingerprint_stream_requests_totalcounterStreaming requests received.
corelayer_fingerprint_upstream_failures_totalcounterUpstream transport failures.
corelayer_fingerprint_observations_dropped_totalcounterObservations dropped from the bounded queue.
corelayer_fingerprint_policy_detections_totalcounterObserve-only policy detections.
corelayer_fingerprint_anomaly_events_totalcounterLBF anomaly events.
corelayer_fingerprint_spool_itemsgaugeItems currently queued in the disk spool.
corelayer_fingerprint_spool_bytesgaugeBytes currently used by the disk spool.
corelayer_fingerprint_upload_successes_totalcounterSuccessful ingest batches sent to the control plane.
corelayer_fingerprint_upload_failures_totalcounterFailed ingest attempts.
corelayer_fingerprint_calibration_samplesgaugeSamples in the current baseline.
corelayer_fingerprint_calibration_stategaugeLabel vector with calibrating, active, and stale states.

Session tracking

The agent groups exchanges into sessions so the LBF and CBE engines can reason about multi-turn behaviour. Session IDs are derived per process using an ephemeral HMAC key. The source material is never stored or reported.

Resolution order:

  1. X-CoreLayer-Session-ID header, if present. Use this for explicit session control.
  2. The user field in the OpenAI request body.
  3. A privacy-preserving fingerprint of the connection metadata (remote address, user agent, authorization header). This is a last resort and may group unrelated requests.

Sessions are bounded by sessions.ttl, sessions.max_sessions, and sessions.max_turns. Idle sessions are evicted by TTL; when the LRU ceiling is reached, the least recently active session is removed.

Privacy and content capture

By default, prompt and response content never leaves the agent process. Telemetry sent to the control plane contains only structured metadata: token counts, tool names, anomaly scores, and detection codes.

When capture_content is true, anomaly and detection events include redacted snippets (up to 2048 characters each). The redaction pipeline strips API keys, bearer tokens, private keys, JWTs, email addresses, SSNs, phone numbers, and credit card patterns before the evidence is written to the spool. Enabling or disabling content capture creates a new immutable dashboard revision and requires a reinstall.

Credential headers are never copied

The LCAC engine reads identity and namespace from configured headers, but Authorization, Cookie, X-API-Key, and other credential headers are rejected at config validation. They cannot be mapped into LCAC attributes or telemetry.

Network requirements

DirectionDestinationWhen
Inbound TCP 8090From the protected application or internal load balancer onlyAlways
Outbound HTTPSupstream.url (your OpenAI-compatible endpoint)Always
Outbound HTTPScontrol_plane.url (CoreLayer control plane)Always
Outbound HTTPSget.corelayersecurity.com, ghcr.ioInstallation only
Outbound DNSCustomer resolverAlways

No inbound control-plane connection is required. If control-plane egress is temporarily blocked, model traffic continues and telemetry is queued under the bounded spool. A full spool drops the oldest items rather than interrupting inference.

File layout

All three installation methods (Docker, systemd, Helm) use the same paths inside the service boundary:

PathPurpose
/etc/corelayer/agent.yamlConfiguration file (read-only after startup).
/var/lib/corelayer/fingerprint/credential.jsonRuntime credential written after enrollment (mode 0600).
/var/lib/corelayer/fingerprint/calibration.jsonBehavioural baseline state.
/var/lib/corelayer/fingerprint/spool/Encrypted telemetry queue.
/var/lib/corelayer/fingerprint/spool.keyAES-256 spool encryption key.

Verifying a release

Every versioned directory includes a SHA256SUMS manifest that the release workflow signs keyless with its GitHub identity. The install script verifies the signature automatically when cosign is present and falls back to the checksum alone otherwise.

Terminal
base=https://get.corelayersecurity.com/agent/v0.1.0
curl -fsSLO "$base/SHA256SUMS"
curl -fsSLO "$base/SHA256SUMS.sig"
curl -fsSLO "$base/SHA256SUMS.pem"
cosign verify-blob SHA256SUMS \
  --signature SHA256SUMS.sig \
  --certificate SHA256SUMS.pem \
  --certificate-identity-regexp '^https://github.com/' \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com
sha256sum -c SHA256SUMS

Removal and data

Stopping or upgrading the agent does not delete the baseline, spool, or runtime credential. Preserve the data directory or PVC for in-place binary upgrades. To remove all local state, stop the service first, revoke the installation in the dashboard, then delete /var/lib/corelayer/fingerprint, the Compose volume, or the Kubernetes PVC. Deleting state starts a new calibration window and requires a fresh enrollment token.

Troubleshooting

The agent exits at startup

  • Config permissions. The YAML file must not be group-writable or world-writable. Check with ls -l /etc/corelayer/agent.yaml.
  • Missing enrollment token. On first startup, the environment variable named in enrollment_token_env must contain the dashboard token. Once a runtime credential has been written, the variable is no longer needed.
  • Validation errors. The agent validates every field strictly. A missing required field, an invalid URL, or overlapping file paths (credential, calibration, spool) will print a specific error and exit.

Calibration stays in "calibrating"

Both min_samples and min_duration must be met. If traffic is low, reduce min_samples or wait longer. Only clean exchanges count: upstream errors, policy detections, truncated responses, and incomplete streams are excluded from calibration.

No events appear in the dashboard

  • Check /readyz. If it returns 503, the background workers have not started.
  • Check the corelayer_fingerprint_upload_failures_total metric. A non-zero value means the control plane is rejecting batches or is unreachable.
  • Check corelayer_fingerprint_spool_items. Items queuing up means delivery is blocked. Check network egress to the control plane URL.

Upstream latency increased

The agent adds no computation to the response path. Observation parsing happens asynchronously after the response has been delivered. If latency increases, check the network path between the agent and the upstream rather than the agent itself. The /metrics endpoint shows upstream failure counts for diagnosis.