Logs
Field-level reference for firewall log entries and the query and streaming API.
A firewall log entry records one rule decision on one package request. For reading them in practice, see View logs; for how they relate to the other records, see Observability.
Entry shape
{
"timestamp": "2026-07-03T09:14:02Z",
"user": "user-7d2f...",
"request": "8f4c2e...",
"interaction": "build-4711",
"userAgent": "npm/10.8.1 node/v22.4.0",
"remoteAddress": "203.0.113.7",
"firewall": "3e7f5cb806f26e3beae2",
"firewallVersion": 12,
"upstream": "npmjs",
"rule": "block-critical-vulns",
"executionPhase": "download",
"blocked": true,
"ecosystem": "npm",
"packageName": "lodash",
"version": "4.17.20",
"published": "2020-08-13T16:53:52Z",
"message": "Block critical vulnerabilities",
"output": { "vulnerabilities": ["CVE-2020-8203"] }
}Fields
| Field | Type | Description |
|---|---|---|
timestamp | string | When the decision was made |
user | string | Who made the request, as an opaque user ID (the token's OIDC subject), not an email or display name. PATs resolve to the user; SATs to the token's identity. The dashboard resolves IDs to names where it can |
request | string | Request ID. Also shown in blocked-install error messages, which is how a developer's error finds this entry |
interaction | string | Interaction ID from the token suffix, if any |
userAgent | string | Client user agent |
remoteAddress | string | Client address |
firewall | string | Firewall ID the request hit |
firewallVersion | number | Config version the request was evaluated under |
sourceFirewall | string | Firewall the matched rule came from, when it was inherited. Absent for the firewall's own rules |
sourceFirewallVersion | number | Config version of sourceFirewall |
upstream | string | Upstream that served or would have served the package |
rule | string | Rule that matched |
exception | string | Exception ID, when an exception allowed the request. Message is EXCEPTION |
exceptionSourceFirewall | string | Firewall the applied exception came from, when it was inherited. Absent for the firewall's own exceptions |
exceptionSourceFirewallVersion | number | Config version of exceptionSourceFirewall |
executionPhase | string | versions, download, or upload. Reflects the request, not the matched rule's phase: a versions rule that matches during an artifact fetch is recorded as download, so versions entries always come from metadata requests |
blocked | boolean | Whether the effect blocked the request |
ecosystem | string | Package ecosystem |
packageName | string | Package name |
version | string | Package version |
published | string | The version's publish date, when known |
message | string | Rule description, or rule-specific message such as Malware detected in npm/example@1.0.0: ... |
output | object | Rule-specific detail: vulnerability IDs and scores; malware finding summary, scanner, confidence, and signals; redacted secrets findings |
One request can produce several entries: each matching log-effect rule writes one, and a block ends the sequence.
Query API
GET /v1/<namespace-id>/log| Parameter | Description |
|---|---|
firewall | Filter to one firewall |
user | Filter to a specific user, by raw user ID, not display name |
allUsers | true for entries from everyone. Mutually exclusive with user |
search | Free-text search |
limit | Entries per page. Default 100, capped at 1000 |
before | Opaque cursor from a previous response's nextCursor, to fetch the next older page |
Without user or allUsers, the server returns the caller's own entries; this default is server-side, not a CLI convenience. Reading logs requires only namespace access.
{
"entries": [],
"nextCursor": "MTc1MTUzMjA0MjAwMDAwMDAwMDoxNDIz"
}Entries are newest first. nextCursor is an opaque token: pass it back as before for the next page, and treat an empty value as the end of the results. Do not parse it. An invalid limit or before is answered with 400.
Streaming
GET /v1/<namespace-id>/log/streamServer-sent events with the same parameters: 10 entries of backfill, then new entries as they happen, with a heartbeat every 20 seconds. This is what bsfw logs --tail and the dashboard's live view consume.
Related
- How-to: View logs, Investigate a blocked install
- Concept: Observability
- Reference: CLI, API