Sandfly Security
Sandfly Security is an agentless intrusion detection and threat hunting platform for Linux. RunReveal polls the Sandfly results API and ingests each scan result, giving you a searchable, long-term record of every detection across your fleet: suspicious processes, tampered files, rogue users, hidden kernel modules, and more.
Sandfly Security is a Pro plan source. RunReveal polls your Sandfly server every 5 minutes.
How It Works
RunReveal authenticates to your Sandfly server with a dedicated API user, then reads results from the results API (POST /v4/results).
To avoid gaps or duplicates, RunReveal synchronizes on Sandfly's monotonic sequence_id rather than on timestamps. Sandfly explicitly recommends this: result timestamps are not guaranteed to be ordered, but sequence_id never decreases. When you first connect the source, RunReveal calls GET /v4/results/getMaxID to record the current high-water mark and then collects every result created after that point. Historical results from before the source was connected are not backfilled.
Setup
To connect Sandfly you need three things: your Sandfly server URL, and the username and password of a dedicated API user.
Step 1: Create a Sandfly API user
Create a dedicated API user for RunReveal rather than reusing a person's login. Assign it the api_result_read role — an API-only, read-only role scoped to results and host data. This follows least-privilege and keeps the account out of the web interface.
You must be a Sandfly admin to create users.
In the Sandfly web interface, go to Settings → Account Settings → User Accounts.
Click Add User and fill in the form:
- User Type:
Local(Sandfly manages the login and password) - Username: a name you'll recognize, for example
runreveal - Password: a strong password — you'll paste this into RunReveal
- Full Name: e.g.
RunReveal Integration - Roles: select api_result_read
Click Finish to create the user, then record the username and password for the next step.
The api_result_read role grants read access to results and host data without web-interface access, which is exactly what RunReveal needs. See Sandfly's Adding Users guide and the API Endpoint Role Security Matrix for the full permission breakdown.
Step 2: Add the source in RunReveal
- Go to Sources in RunReveal
- Click the Sandfly Security source tile
- Give it a Source Name
- Enter your Sandfly Server URL — the base URL of your Sandfly server, e.g.
https://sandfly.example.com. RunReveal appends the API path automatically. - Enter the Username and Password for the API user from Step 1
- (Optional) Enable Skip TLS certificate verification if your Sandfly server uses a self-signed or otherwise untrusted certificate
- Click Connect Source
Your Sandfly server must be reachable from RunReveal over HTTPS on a public address. Self-hosted servers behind a private network or firewall need to allow inbound access from RunReveal.
Only enable Skip TLS certificate verification when your Sandfly server presents a self-signed or internal certificate. It disables certificate and hostname validation for requests to that server, so prefer installing a trusted certificate where possible.
Verify It's Working
New results should begin flowing within a few minutes of the next Sandfly scan. Because RunReveal starts from the current sequence_id, you'll see data once Sandfly produces new results after the source is connected.
You can validate we are receiving your logs by running the following SQL query.
Schema
The following columns are exposed for this source. RunReveal applies schema normalization across all sources, ensuring uniform field names and data types for cross-source queries and reusable detection logic.
Table: sandfly_logs (51 columns)
sandfly_logs (51 columns)| Column | Type |
|---|---|
workspaceID | String |
sourceID | String |
sourceType | String |
sourceTTL | UInt32 |
receivedAt | DateTime |
id | String |
eventTime | DateTime |
eventName | String |
eventID | String |
srcIP | String |
srcASCountryCode | String |
srcASNumber | UInt32 |
srcASOrganization | String |
srcCity | String |
srcConnectionType | String |
srcISP | String |
srcLatitude | Float64 |
srcLongitude | Float64 |
srcUserType | String |
dstIP | String |
dstASCountryCode | String |
dstASNumber | UInt32 |
dstASOrganization | String |
dstCity | String |
dstConnectionType | String |
dstISP | String |
| Column | Type |
|---|---|
dstLatitude | Float64 |
dstLongitude | Float64 |
dstUserType | String |
actor | Map(String, String) |
tags | Map(String, String) |
resources | Array(String) |
serviceName | String |
enrichments | Array(Tuple(data Map(String, String), name String, provider String, type String, value String)) |
readOnly | Bool |
rawLog | String |
resultId | String |
sequenceId | Int64 |
externalId | String |
hostname | String |
hostId | String |
ipAddr | String |
nodeName | String |
queueName | String |
sandflyName | String |
status | String |
severity | UInt8 |
resultType | String |
engine | String |
keyData | String |
endTime | String |
Helpful Links
- Sandfly Results API - Reference for the results endpoint RunReveal polls
- Adding Users - How to create the API user in Sandfly
- API Endpoint Role Security Matrix - Detailed role permissions, including api_result_read