Skip to content

Shield360 Edge: protection and AI controls in front of any app

Shield360 Edge is a reverse proxy you put in front of an app. It gives you two things without touching the app’s code:

  • Protection for the app’s own routes: a web application firewall with the OWASP Core Rule Set, virtual patches, upload checks, reflected-XSS reports, decoys and rate limits.
  • An AI gateway for routes that call an AI provider: your organization’s AI policy, approved models, sensitive-data masking, prompt-injection checks, budgets and cost.
client ──► Shield360 Edge ──► your app (app routes)
└──► AI provider (routes with ai: true)

Edge is one binary, shield360-edge. Your Shield360 server serves it for Linux, macOS and Windows, and it is also published as a container image, 959429674945.dkr.ecr.us-east-2.amazonaws.com/shield360-selfhosted:edge-<version>, for linux/amd64 and linux/arm64. The image is in the private Shield360 registry: sign in with the access Shield360 gives your account, as for the self-hosted image. Every setting is in the Edge configuration reference.

Install Edge

Install the binary from your Shield360 server. Replace https://app.shield360.ai with your own address if you self-host.

Terminal window
curl -fsSL https://app.shield360.ai/api/edge/install-edge.sh | sh
Terminal window
iwr -useb https://app.shield360.ai/api/edge/install-edge.ps1 | iex

The script reads the version and sha256 of each platform’s binary from /api/edge/targets, downloads it from /api/edge/download/<file>, refuses it if the sha256 does not match, and installs it to $HOME/.shield360/bin/shield360-edge (%USERPROFILE%\.shield360\bin\shield360-edge.exe on Windows, added to your user PATH). WAF & RASP → Edge instances shows the same command for your server, with the binaries for each operating system and architecture.

Write a configuration

WAF & RASP → Edge instances → Install writes this file for you: enter the app name, the app’s address, the port and monitor or block, and copy the result. The enroll and container commands there already carry your server and this environment’s config public key. Or save this as edge.yaml. It forwards everything to an app on localhost:3000; see the configuration reference for routes, modes and limits.

listen: ":8080"
admin_listen: ":9901"
shield360:
url: https://app.shield360.ai
cache_dir: ./edge-cache
routes:
- name: web
upstream: http://localhost:3000
app: my-web-app
rasp:
mode: monitor
waf:
enabled: true
mode: monitor
Enroll and start it

Make an enrollment token in WAF & RASP → Edge instances (see Connect Edge to Shield360), then:

Terminal window
export SHIELD360_API_KEY=<the app's API key>
export SHIELD360_CONFIG_PUBLIC_KEY='<JWK from the app’s Runtime protection settings>'
export SHIELD360_EDGE_ENROLLMENT_TOKEN=<s360e_… token>
shield360-edge enroll --config edge.yaml
shield360-edge --config edge.yaml

Clients now use http://localhost:8080.

Check a configuration without starting the proxy:

Terminal window
shield360-edge --config edge.yaml --check

The image runs as a non-root user on a read-only root file system. It has a sample configuration at /etc/shield360-edge/edge.yaml; mount your own over it, and give /var/lib/shield360-edge a volume so the enrollment and the last verified configs survive a restart.

Terminal window
docker run -d --name shield360-edge -p 8080:8080 \
-e SHIELD360_URL=https://app.shield360.ai \
-e SHIELD360_API_KEY=<the app's API key> \
-e SHIELD360_CONFIG_PUBLIC_KEY='<JWK from the app’s Runtime protection settings>' \
-e SHIELD360_EDGE_ENROLLMENT_TOKEN=<s360e_… token> \
-v "$PWD/edge.yaml:/etc/shield360-edge/edge.yaml:ro" \
-v shield360-edge-cache:/var/lib/shield360-edge \
--read-only --security-opt no-new-privileges:true \
959429674945.dkr.ecr.us-east-2.amazonaws.com/shield360-selfhosted:edge-latest

Sign in to the registry first (how). Pin a version (for example 959429674945.dkr.ecr.us-east-2.amazonaws.com/shield360-selfhosted:edge-1.0.2) in production instead of edge-latest. In the container, the upstream is another container or host, not localhost: in the sample below it is http://app:3000.

docker-compose.yml: Edge in front of an app
# export SHIELD360_URL=https://app.shield360.ai
# export SHIELD360_API_KEY=... # the app's API key
# export SHIELD360_CONFIG_PUBLIC_KEY='...' # Runtime protection settings
# export SHIELD360_EDGE_ENROLLMENT_TOKEN=... # Settings -> Data collection -> Deployment -> Edge
# docker compose up -d
services:
shield360-edge:
image: 959429674945.dkr.ecr.us-east-2.amazonaws.com/shield360-selfhosted:edge-latest
restart: unless-stopped
environment:
SHIELD360_URL: ${SHIELD360_URL:?set SHIELD360_URL}
SHIELD360_API_KEY: ${SHIELD360_API_KEY:?set SHIELD360_API_KEY}
SHIELD360_CONFIG_PUBLIC_KEY: ${SHIELD360_CONFIG_PUBLIC_KEY:-}
# Enrolls once; the credential is kept in the cache volume.
SHIELD360_EDGE_ENROLLMENT_TOKEN: ${SHIELD360_EDGE_ENROLLMENT_TOKEN:-}
ports:
- "8080:8080"
volumes:
- ./edge.yaml:/etc/shield360-edge/edge.yaml:ro
- shield360-edge-cache:/var/lib/shield360-edge
read_only: true
security_opt:
- no-new-privileges:true
healthcheck:
# The image has no shell or curl: probe :9901/readyz from your orchestrator.
disable: true
depends_on:
- app
# Replace with your application. edge.yaml forwards to app:3000.
app:
image: hashicorp/http-echo:1.0
command: ["-listen=:3000", "-text=hello from the app"]
volumes:
shield360-edge-cache:

Each image is signed with cosign by the workflow that built it. To check one before you run it:

Terminal window
cosign verify 959429674945.dkr.ecr.us-east-2.amazonaws.com/shield360-selfhosted:edge-1.0.2 \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
--certificate-identity 'https://github.com/ThinkfleetAI/Shield360/.github/workflows/release-edge.yml@refs/heads/main'

Health checks: GET :9901/healthz answers while the process is up, and GET :9901/readyz while it is listening and not draining.

  1. Works out the client’s address, trusting X-Forwarded-For only from proxies you list.
  2. Picks the route by host, then by the longest path prefix.
  3. Decoys. A request to a decoy path is answered by Edge and marks the client as suspicious. Later requests from that client are blocked or flagged, depending on the action.
  4. Rate limit per client and route (429 over the limit).
  5. Body limit (413 over the limit).
  6. App routes with waf on: the web application firewall checks the request line, headers and body against the OWASP Core Rule Set.
  7. App routes: records the request’s input and runs the runtime protection request checks: virtual patches and upload file names.
  8. Forwards the request, streaming bodies and passing websockets through.
  9. App routes: checks HTML responses for reflected XSS in the background. This only reports.

AI routes skip steps 6, 7 and 9 and go through the same enforcement as the Shield360 AI proxy: allowed, warned or blocked AI vendors, approved models, sensitive data in prompts (warn, mask or block), and prompt injection. Edge counts each answer’s tokens and list-price cost, and applies budgets.

Everything follows the runtime protection rules: monitor by default, the app’s signed config wins when a key is pinned, and inspection fails open unless a route says fail_closed: true.

An app route can run OWASP Coraza with the OWASP Core Rule Set, embedded in Edge, so there is nothing to download. It catches the common web attacks by their shape: SQL injection, cross-site scripting, remote command execution, local file inclusion, PHP and Java injection, protocol abuse and scanners.

routes:
- name: shop
upstream: http://shop:8080
waf:
enabled: true
mode: monitor # or block
paranoia_level: 1 # 1 to 4: higher catches more and needs more exclusions
inbound_threshold: 5 # the anomaly score that counts as an attack (5 = one critical rule)
exclude_rules: [942430] # rule ids to turn off for false positives
rules: # your own SecLang rules, after the rule set
- SecRule REQUEST_URI "@beginsWith /internal" "id:10001,phase:1,deny,status:403,msg:'internal path'"
SettingDefaultWhat it does
enabledfalseTurns the firewall on for the route. Not available on AI routes, which have their own checks.
modemonitormonitor reports attacks and forwards the request; block answers 403
paranoia_level1The rule set’s paranoia level
inbound_threshold5The anomaly score a request must reach to count as an attack
exclude_rules[]Rule set rules to remove by id
rules[]Extra SecLang directives

The rule set scores each request: every rule that matches adds to its anomaly score, and a request that reaches inbound_threshold is an attack. In monitor mode Edge reports it as a waf.matched event and forwards the request; in block mode it answers 403 and reports waf.blocked. Each event names the route, the matched rule ids and the attack categories (sqli, xss, rce, …), never the matched input, which is the request’s own data. Start in monitor, add exclude_rules for the false positives you see, then switch to block. If the firewall fails on a request, it is forwarded and reported as waf.failed, unless the route sets fail_closed: true.

The events show in Monitor → Detections → Runtime events (source Web firewall) and in All detections, once Edge sends its telemetry to Shield360 (telemetry.otlp_endpoint). Each event is a span event on the request’s own span, so it opens the request’s trace. Filter by decision (let through, blocked, not checked), attack category, route and app; the chart counts events over time by decision. Reading them needs Data protection access.

If your app has a chatbot, assistant or AI search box, Edge can check what people type into it before your app sees it. Add ai_app to the app’s route:

routes:
- name: support
upstream: http://support-app:3000
ai_app:
mode: monitor # or block
prompt_fields: # where the prompt sits in the JSON request
- message
- messages.*.content
max_prompt_chars: 8000 # optional
CheckWhat it finds
Prompt injectionText trying to override your app’s instructions, such as “ignore all previous instructions”
Sensitive dataAPI keys, passwords, private keys, card numbers, social security numbers and similar
Prompt lengthRequests longer than max_prompt_chars

Turn a check off with injection: false or sensitive_data: false.

prompt_fields uses dot-separated keys, with * for every item in a list. Without it, Edge checks prompt, message, input, query, question and messages.*.content. Only JSON requests are checked.

In monitor mode Edge reports what it found and forwards the request. In block mode the person sees a message asking them to remove sensitive details, and your app never receives the request. The message doesn’t say which check matched. Allow-listed addresses are reported but never blocked.

Events show the check, the field and the categories or kinds found, never the text people typed. These findings don’t count towards an address’s reputation, because someone pasting their own details isn’t an attacker. To limit how often each person can send prompts, add a path rate limit keyed on your user header.

Start in monitor mode and review the events before you block.

These checks cover what people send in. Edge doesn’t yet check your AI app’s answers.

Your security team can manage Edge’s blocking in WAF & RASP → WAF, without editing each instance’s file. The tab opens with what the firewall does on each route, and Block there moves one route from monitor to block. WAF & RASP → Apps says for each route whether the value is an environment default, set for the route, or left to the instance’s own file, which the console cannot change. It shows Applied only once Edge reports that mode on an event. An Edge instance that is not enrolled receives none of these settings, and the page says so. WAF & RASP is part of the Security module. Enrolled instances apply a change at their next policy refresh, without a restart. Each setting is added to an instance’s own file, or replaces it where noted. A setting Edge cannot apply is refused when you save it, and Edge drops one that still fails its own checks, never applying it halfway.

SectionWhat you setHow it combines with the file
Firewall, every route and route overridesWAF on or off, mode, paranoia level, anomaly threshold, and the rate limit per client IP (requests a second and burst)Replaces the file’s value for each field you set
ExclusionsRule ids turned off on part of a routeAdded
Rule packsVirtual patches for known CVEsAdded
Client access listsIPs and CIDRs that are never blocked, or always get a 403Added
DecoysWhat happens to a client that requests a decoy (monitor or block), how long it stays marked, extra decoy pathsReplaces the action and time; paths are added
Automatic IP banFindings (WAF matches, decoy hits, OpenAPI violations, runtime protection blocks) within a window that ban a client, for how long, and monitor or blockReplaces the file’s reputation when managed here
Threat listsLists of known-bad IPs, such as Spamhaus DROP or Tor exit nodes, each with monitor or blockAdded

Threat lists from Shield360 are fetched only over HTTPS and only from public addresses: Edge refuses a list whose host resolves to a private, loopback or link-local address. Changing these settings needs permission to change what is collected, and every change is recorded in the audit log.

Bans, decoy marks and rate limits are counted on each instance and cleared by a restart (see Limits).

In Detections → Runtime events → Edge, open an event and choose Block this IP. If the event carries only the client’s network, the button reads Block this network. The address is added to the client access list’s deny entries for this environment, and enrolled instances apply it within about 15 seconds. Every request from that address gets a 403, even if it is on the allow list. Undo block removes it. You can also review and remove blocked addresses in Firewall and blocking.

Blocking needs permission to change what is collected, and each block and unblock is recorded in the audit log with the address. Private, loopback, link-local and other internal addresses can’t be blocked this way, nor networks wider than a /16 for IPv4 or a /32 for IPv6. Those limits stop a block from cutting off your own load balancers.

An event shows the full client address only when the instance reports it (telemetry.client_ip: full), and only to people who can block it. Everyone else who can read runtime events sees the client’s /24 or /48 network.

An Edge event that was only monitored also offers the rule that would have stopped it. Each one asks you to confirm, because it reaches past the one client, and each has an undo.

  • Block WAF matches on a route switches that route’s web application firewall to block. Every request that matches a WAF rule on the route gets a 403, for every client. Check for false positives first.
  • Block Deception in an app sets Edge’s decoy action to block, for every app behind Edge in the environment. The client’s later requests are refused for as long as it stays marked suspicious.

Rate limits, auto-ban and threat lists opens Firewall and blocking for the rest of Edge’s controls.

A finding about a runtime attack has a Respond section under its summary. It lists the clients Edge saw doing what the alert reports, each with Block this IP, and offers the rule that stops that attack.

Shield360 reads the clients from Edge’s own events, by app, kind of attack and time. It never reads them from the finding’s text. Apps that aren’t behind Edge have no clients to list, because their SDKs don’t report client addresses.

The section shows only what your role can do. Blocking clients needs permission to change what is collected. Blocking an attack type needs permission to manage policies. If no Edge instance is enrolled in the environment, the section says so: a block is saved, but nothing enforces it until an instance is enrolled.

An enrolled Edge instance reads its environment’s AI policy, reports its decisions and spend, and shows with its last heartbeat in Shield360.

Make an enrollment token

Open WAF & RASP → Edge instances and make an enrollment token (s360e_…). It is shown once.

Give it to Edge

Put the token in a file (shield360.enrollment_token_file) or in SHIELD360_EDGE_ENROLLMENT_TOKEN, and set shield360.url and shield360.cache_dir.

Start Edge

Start Edge, or run shield360-edge enroll --config edge.yaml first. Edge exchanges the token for its own credential and keeps it in its cache directory.

From then on:

  • AI policy. AI routes use the environment’s AI policy and refresh it regularly. If Shield360 can’t be reached, the last policy stays in force. If an administrator turned on fail-closed for the AI guard, AI requests are refused while no trustworthy policy is in force.
  • Decisions and spend. Guard decisions, prompt-injection detections and budget refusals show with your other AI decisions. Token usage shows in Cost as billed API usage.
  • Per-key budget. Set it on the same tab. It applies to every AI route without a budget of its own.
  • Instances. WAF & RASP → Edge instances lists each instance with its status, health, version, routes, counters and last heartbeat. Revoke cuts an instance off.
  • Rate limits, decoy marks and budgets are kept in memory per instance. With several replicas, each counts on its own, and a restart forgets them.
  • Edge sees requests and responses, not the app’s SQL, shell, file or outbound calls. Those checks need the SDK’s runtime protection.
  • Only the first 1 MiB of a body is inspected, and compressed bodies are not.
  • Edge serves plain HTTP. Terminate TLS in front of it.

Making or revoking tokens, revoking instances and changing the budget needs both Enroll computers and Change what is collected. Viewing instances needs View computers and people.