IAST agents
Install the Safeguard IAST agent in your Java, Node.js or Python application. What it reports, the agent token it needs, configuration, overhead and uninstall.
Availability
Always-on reporting is switched on per workspace. If you do not see the IAST agents cards under Integrations, ask your Safeguard contact. The agent packages themselves are public on registry.safeguard.sh.
What it does
The Safeguard IAST agent runs inside your application and watches untrusted request input travel to a dangerous operation: a SQL statement, a shell command, a file path. When request input reaches one of those operations, the agent reports the flow with the route, the parameter, and the file and line of the code that consumed it. Findings appear as IAST vulnerabilities on the project you chose when you issued the agent token, de-duplicated by route, sink and stack, with a "last seen" for every agent process. The cards are under Integrations > Configure > IAST agents, one per language.
There are agents for Java (and every JVM language), Node.js (JavaScript and TypeScript) and Python. .NET, Go, Ruby and PHP agents are not available yet.
The agent has two modes:
- Always-on. The agent reports to
https://api.safeguard.sh/gpt/api/v1/iastfor as long as the application runs. This is what this page sets up. - Scan mode. The agent reports to the collector a running Safeguard IAST scan hosts, only for the length of the scan. That mode is configured on the scanner and works as before.
Public vs private
| Public | Private | |
|---|---|---|
| What you enter | Nothing: installing the agent needs no credential | An agent token in the application's environment |
| Credential needed | None to download the packages | A Safeguard agent token (sg_iast_...) to report |
| What you get | The agent package or image | Findings delivered into one project |
Supported auth methods
| Method | Use it when | Notes |
|---|---|---|
Agent token (sg_iast_...) | Always-on reporting from an installed agent | One token per integration (one application, one project). Sent as Authorization: Bearer. |
| Scan agent token | Scan mode only | Set on the IAST scanner; valid only while that scan runs |
Permissions required
The agent token only lets an agent send reports. It cannot read findings, change settings or reach any other Safeguard API.
Agent token
| Permission | Required? | What Safeguard uses it for |
|---|---|---|
| Report to the always-on collector | Required | Accepting hello and report requests from the agent and filing findings into the token's project |
| Workspace administrator, to issue the token | Required | Only a workspace administrator, signed in, can issue, rotate or revoke an agent token |
Least privilege: issue one token per application, so revoking one never interrupts another.
Token types
| Token type | Works? | Notes |
|---|---|---|
Agent token (sg_iast_...) | Yes | Shown once when issued or rotated; Safeguard stores only its SHA-256 |
| Registry pull token | Not needed | The agent packages are public |
| Personal or API keys | No | The collector accepts agent tokens only |
Expiry: agent tokens do not expire. Rotate them on your own schedule, and revoke a token as soon as an application is retired.
What we never need: database credentials, cloud credentials, source code access or write access to anything in your environment.
Step-by-step setup
Issue an agent token
- Open Integrations, choose the Configure tab and the IAST agents section.
- Under Agent tokens, click Issue token, name the application and choose the project its findings go to.
- Copy the token. It is shown only once. Store it as a secret (a Kubernetes Secret, your CI secret store, a vault), never in an image or a repository.
Install the agent
The packages are public on registry.safeguard.sh and signed. Pick your language.
Java (any JVM language). Download the JAR, or add it as a Maven or Gradle dependency.
curl -fsSLo iast-agent.jar https://registry.safeguard.sh/maven/sh/safeguard/iast-agent/1.0.1/iast-agent-1.0.1.jar
SAFEGUARD_IAST_TOKEN=sg_iast_... java -javaagent:iast-agent.jar -jar app.jar<repositories>
<repository><id>safeguard</id><url>https://registry.safeguard.sh/maven/</url></repository>
</repositories>
<dependency>
<groupId>sh.safeguard</groupId>
<artifactId>iast-agent</artifactId>
<version>1.0.1</version>
<scope>runtime</scope>
</dependency>repositories { maven { url = uri("https://registry.safeguard.sh/maven/") } }
configurations { create("safeguardIast") }
dependencies { "safeguardIast"("sh.safeguard:iast-agent:1.0.1") }Requests to any servlet (javax or jakarta: Tomcat, Jetty, Undertow, Spring MVC) and to the JDK's com.sun.net.httpserver are captured with no code change.
Node.js (JavaScript and TypeScript). Copy the agent out of the public image and preload it:
COPY --from=registry.safeguard.sh/iast/agent:1.0.1 /opt/safeguard/node /opt/safeguard/node
ENV NODE_OPTIONS="--require=/opt/safeguard/node/register.js"Or install the package from registry.safeguard.sh. Point the @safeguard-sh scope at the registry in .npmrc first, then install and preload it:
# .npmrc
@safeguard-sh:registry=https://registry.safeguard.sh/npm/
npm install @safeguard-sh/iast@1.0.1
SAFEGUARD_IAST_TOKEN=sg_iast_... node --require @safeguard-sh/iast/register server.jsThe package was first published as @safeguard/iast. That name still installs from registry.safeguard.sh but is deprecated: on npmjs.com the @safeguard scope belongs to someone else, so use @safeguard-sh/iast, Safeguard's own scope. The preload captures every request on an http or https server with no code change. With Express, also mount the middleware first, so the agent sees what Express parses:
app.use(require('/opt/safeguard/node').middleware());Python.
pip install --index-url https://registry.safeguard.sh/pypi/simple/ safeguard-iast==1.0.1
SAFEGUARD_IAST_TOKEN=sg_iast_... safeguard-iast-run gunicorn app:appsafeguard-iast-run runs any Python program under the agent, gunicorn's forked workers included. Flask and Django requests are captured with no code change. For ASGI apps (FastAPI, Starlette), wrap the app: app = safeguard_iast.instrument_asgi(app).
Docker. Copy the agent out of the public image:
COPY --from=registry.safeguard.sh/iast/agent:1.0.1 /opt/safeguard/java/iast-agent.jar /opt/safeguard/iast-agent.jar
ENV JAVA_TOOL_OPTIONS="-javaagent:/opt/safeguard/iast-agent.jar"The image also holds the Node.js agent at /opt/safeguard/node and the Python agent at /opt/safeguard/python.
Kubernetes. An init container copies all three agents into a shared volume:
spec:
initContainers:
- name: safeguard-iast
image: registry.safeguard.sh/iast/agent:1.0.1
args: ["/safeguard"]
volumeMounts:
- { name: safeguard-iast, mountPath: /safeguard }
containers:
- name: app
env:
- name: SAFEGUARD_IAST_TOKEN
valueFrom: { secretKeyRef: { name: safeguard-iast, key: token } }
- name: SAFEGUARD_IAST_APP
value: acme-api
# Java
- name: JAVA_TOOL_OPTIONS
value: "-javaagent:/safeguard/java/iast-agent.jar"
# Node.js (instead of the Java line)
# - name: NODE_OPTIONS
# value: "--require=/safeguard/node/register.js"
# Python (instead of the Java line)
# - name: PYTHONPATH
# value: "/safeguard/python/safeguard_iast/bootstrap:/safeguard/python"
volumeMounts:
- { name: safeguard-iast, mountPath: /safeguard, readOnly: true }
volumes:
- name: safeguard-iast
emptyDir: {}kubectl create secret generic safeguard-iast --from-literal=token=sg_iast_...Configuration
| Variable | Meaning |
|---|---|
SAFEGUARD_IAST_TOKEN | The agent token. A token starting sg_iast_ selects always-on mode. |
SAFEGUARD_IAST_ENDPOINT | Collector base URL. Default https://api.safeguard.sh/gpt/api/v1/iast. |
SAFEGUARD_IAST_APP | The application name shown against findings and agents. |
SAFEGUARD_IAST_ENABLED | 0 turns an always-on agent off without uninstalling it. In scan mode, 1 turns it on. |
SAFEGUARD_IAST_COLLECTOR | Scan mode only: the scan's collector, for example http://scanner:7878. |
SAFEGUARD_IAST_DEBUG | 1 logs what the agent instrumented. |
Check it is reporting
Start the application. Its log shows safeguard-iast 1.0.1 attached (... always-on ...). Within five minutes the agent appears under Last seen on the language card. Findings appear on the project as the application serves requests that reach a vulnerable operation.
Verify the signatures
Every package carries a signature, an SBOM and signed provenance, made with the same key as Safeguard Gold:
cosign verify --key https://registry.safeguard.sh/_gold/keys/cosign.pub --insecure-ignore-tlog registry.safeguard.sh/iast/agent:1.0.1
curl -fsSL https://registry.safeguard.sh/_products/attest/iast/pypi/safeguard-iast/1.0.1/provenanceWebhooks and triggers
This integration has no webhooks. The agent reports as the application runs: findings are batched every 5 seconds, a heartbeat goes out every 5 minutes, and a flow already reported is re-sent at most every 15 minutes with only its new observations.
What we read and store
- Read: inside your process, the agent registers request input (query parameters, headers, cookies, servlet form parameters, parsed bodies in Express) for the length of the request, and checks it at SQL, command, file, SSRF, deserialisation and template operations.
- Stored: for each distinct flow, the vulnerability class, the route (
GET /users/:id), the parameter name and kind, the source and sink symbols with file and line, a redacted excerpt of the value that reached the sink, how often it was seen, and first and last seen. For each agent process, its runtime, version, application name, host and last seen. - Not stored: the raw report and request bodies are never stored. A value that arrived in a body or form field, a cookie or an authorisation header keeps no excerpt at all. Secrets (API keys, tokens, passwords in URLs) are redacted, and query values whose names suggest a secret are replaced.
- No customer data from this integration is sent to third-party LLMs.
What each agent detects
| Agent | Detects | Known limits |
|---|---|---|
| Java | SQL (every JDBC driver), command (Runtime.exec, ProcessBuilder), path (FileInputStream, FileOutputStream), deserialisation, SSRF | Work moved to another thread (@Async, executors) is not tracked. Traces have two frames, source and sink. Reading servlet parameters parses form bodies, as the servlet API does. |
| Node.js | SQL (mysql, mysql2, pg, sqlite3, better-sqlite3, mssql, oracledb, sequelize, knex), command (exec, and spawn/execFile with a shell), path (fs), new Function, SSRF (axios, node-fetch, got), MongoDB | CommonJS only: an application loading its own code as native ESM is not covered. eval cannot be wrapped. Path parameters (/users/:id) are not tracked. |
| Python | SQL (sqlite3, psycopg2/psycopg, PyMySQL, MySQLdb, oracledb, pyodbc), command (os.system, subprocess with a shell), path, eval/exec, SSRF, deserialisation, template injection, log injection, XXE | Values built with f-strings are recovered by recognising the request value at the sink. A value that passes through a C extension loses its taint and is not reported. |
The agents report what they observe on real requests and prefer missing a flow to reporting one that did not happen: parameterised queries, subprocess without a shell and values shorter than 6 characters are never reported.
Overhead
The agent wraps the dangerous operations in process and checks them only while a request is in flight; outside a request a check returns at once. Reporting never blocks a request: findings go on a bounded queue (2,048 entries) drained by a background thread or timer, repeats are counted locally, and at most 10,000 distinct flows are tracked per process. We have not published benchmark figures; measure on a staging copy of your service before you roll out widely.
Troubleshooting
| Message you see | Cause | Fix |
|---|---|---|
collector refused registration (401) or The agent token is not valid. | The token is mistyped, or is not an agent token | Copy the token again, or issue a new one |
The agent token has been revoked. (403) | The token was revoked, or its rotation grace ended | Issue or rotate a token and update the secret |
Always-on IAST agents are not enabled for this workspace. (403) | Always-on reporting is off for your workspace | Ask your Safeguard contact |
Rate limit reached for this agent token. (429) | Many processes report at once | Nothing: the agent waits and retries. Use one token per application. |
The report is over ... bytes (413) | A report was too large | Nothing: the agent sends at most 100 findings per report |
collector at ... not reachable yet | No network route to api.safeguard.sh at start-up | The agent instruments anyway and delivers once it can connect. Allow outbound HTTPS to api.safeguard.sh. |
No attached line in the log | No token in the environment, or SAFEGUARD_IAST_ENABLED=0 | Check the variables reach the process |
Rotation and disconnect
- Rotate: on the card, click Rotate on the token. You can keep the old token working for up to 60 minutes while you update the secret everywhere, then it stops.
- Revoke: click Revoke. The token stops working within 30 seconds; agents using it are refused.
- Uninstall: remove
-javaagent,--requireorsafeguard-iast-run(or the init container and the environment variables) and redeploy. SettingSAFEGUARD_IAST_ENABLED=0turns the agent off without a rebuild. Revoke the token afterwards.
Vendor references
- java.lang.instrument (Java agents), checked 2026-10-17.
- Node.js command-line options: --require, checked 2026-10-17.
- Python site module: sitecustomize, checked 2026-10-17.
- Kubernetes init containers, checked 2026-10-17.
- Sigstore cosign verify, checked 2026-10-17.
Google Artifact Registry
Connect Google Artifact Registry (and public gcr.io images) to Safeguard. The IAM role the service account needs, which credentials work, and step-by-step setup.
Hugging Face
Connect Hugging Face Hub models to Safeguard. The access the user access token needs, which token types work, and step-by-step setup.