Usage
General
Starting the File Inspection Engine
The File Inspection Engine starts the main application process separately from its analysis instances.
The application will start successfully in most cases, except for fatal configuration errors.
- The license is checked during startup.
- Threat data must be downloaded before analysis can begin.
- Analysis instances initialize independently. The application is considered ready when at least one instance is ready, which can be seen in the logs or through the
/status
endpoint.
To verify overall readiness, use the readiness endpoint:
curl http://<host>:<port>/readyz
If the application is ready, this returns 200 OK
.
The /readyz
endpoint is the recommended way to confirm readiness, because it checks not only instance availability but also license validity, threat data availability, and the concurrency limit.
When starting for the first time, the application needs to download threat data. This process may take some time, and the application will only become fully usable once the threat data download is complete, regardless of the messages displayed.
If the static analysis engine fails to initialize or another fatal configuration error occurs, the application will exit. For all other errors, logs will be generated, and the application will continue to run.
Possible Response Status Codes
If present, the errors
and message
fields may contain soft errors (e.g., failing to get detailed threat information from the cloud), but are often empty. Hard errors will be returned as HTTP status 500 Internal Server Error
.
Code | Description | Message |
---|---|---|
200 | The request has succeeded. | N/A |
400 | File size error. | {"error": "Maximum upload file size in bytes is {configured_value}" } |
429 | Concurrency limit reached. | {"error":"The concurrency limit has been reached"} |
429 | High processing load | {"error":"Analysis not accepted due to high processing load"} |
524 | A timeout occurred. | {"error": "The analysis could not be completed within the configured maximum analysis time"} |
File Submissions
POST /scan
To scan a file, make a POST request to http://<host>:<port>/scan
, with the file contents as the raw request body.
- You don't need to set the
Content-Type
header. If set, it will be included alongside every log message related to that submission. - It is recommended to set the
Content-Length
header to prevent files larger than the maximum upload size from partially uploading before getting rejected. - Optionally, you can provide an
external_id
query string parameter that will also be included alongside log messages related to the submission. This parameter can contain any value meaningful to the client application, such as a file name, database ID, or other identifying information.
Examples using curl
Example request:
curl -X POST --upload-file example.docx http://<host>:<port>/scan
Example response:
{
"classification": "OK",
"message": "",
"errors": []
}
Classification: The classification
string will be either "OK"
or "malicious"
.
If paranoid mode is turned on, the classification could also be "suspicious"
.
If with-threat-details
and add-file-type
options are enabled, the response may look like:
{
"classification": "malicious",
"message": "",
"errors": [],
"threat_details": {
"platform": "Script",
"type": "Trojan",
"threat_name": "Script-JS.Trojan.Redirector"
},
"file_type": "Text"
}
Logging:
The following example provides Content-Type
and a custom external ID in the request, both of which can be visible in application logs:
curl -X POST -H 'Content-Type: application/x-tar' --upload-file archive.tar 'http://localhost:8000/scan?external_id=my%20external%20id'
Log example:
This request would create the following log entry, including the external ID:
{
"level": "info",
"process": "fie",
"request_id": "2fd7364b-50c5-4128-ae08-35a819dda62f",
"external_id": "my external id",
"content_type": "application/x-tar",
"component": "http.api",
"request_path": "/scan",
"content_length": 244244480,
"active_concurrency": "1/20",
"time": "2025-09-24T15:25:06.350178812+02:00",
"message": "Upload started"
}
Error handling
If there are any errors, they will be returned in the message
field (deprecated), as well as the errors
field. The message
field will contain the same errors as the errors
array, only it will be a semicolon-concatenated string. For example:
{
"message": "error one; error two; error three",
"errors": ["error one", "error two", "error three"]
}
In some cases, certain errors are expected, and are converted to additional properties inside analysis_information
. For example, if a file hits the decompression factor limit, this error will be logged in errors
and message
, but also present in analysis_information.partial_unpacking
.
{
"errors": ["Exceeds decompression ratio."],
"message": "Exceeds decompression ratio.",
"analysis_information": {
"partial_unpacking": true
}
}
Hash Lookups
Use the following endpoints to check sample classification by sample or hash without triggering static analysis.
Compute hash and perform lookup
POST /check-sample/upload
To use a file to compute its hash and check its classification, make a POST request with the file sample as the raw request body.
Even though the sample is not sent for static analysis, the configured file size limit still applies.
Examples using curl
Example request:
curl -X POST --upload-file sample 'http://localhost:8000/check-sample/upload'
Example response:
{
"classification": "malicious"
}
Classification: The classification
string will be either "OK"
or "malicious"
.
If paranoid mode is turned on, the classification could also be "suspicious"
.
If the with-threat-details
option is enabled, the response may look like:
{
"classification": "malicious",
"threat_details": {
"platform": "Win32",
"type": "Malware",
"threat_name": "Win32.Malware.Heuristic"
}
}
Provide hash and perform lookup
GET /check-sample/hash/{name}/{value}
To check a file's classification by providing its hash, make a GET request using the following path parameters:
name
: Hash type; currently supports onlysha1
value
: SHA1 hash string
Examples using curl
Example request:
curl -X GET 'http://localhost:8000/check-sample/hash/sha1/74577262dad60dc5bf35c692f23300c54c92cb53'
Example response:
{
"classification": "malicious"
}
Classification: The classification
string will be either "OK"
or "malicious"
.
If paranoid mode is turned on, the classification could also be "suspicious"
.
If the with-threat-details
option is enabled, the response may look like:
{
"classification": "malicious",
"threat_details": {
"platform": "Win32",
"type": "Malware",
"threat_name": "Win32.Malware.Heuristic"
}
}
Request Rejection
When a /scan
or /check-sample
upload request reaches an FIE instance, the engine first performs a readiness check before accepting the file for processing.
Depending on the setup, readiness checks can be approached in two ways:
-
Kubernetes Readiness: Point your container's readiness probe to
/readyz
. When a container fails its readiness check, Kubernetes marks the Pod as not ready, and Services automatically stop routing traffic to it. -
External Load Balancer: Configure your load balancer's health check on
/readyz
so only ready instances receive traffic. These probes are helpful to keep traffic away from busy nodes, but they are optional. The engine also performs its own readiness check for each file upload.
Depending on the delay between the readiness check and the file submission, it is possible that the application returns a ready state, but the file can still be rejected if the conditions change. Such files will have to be resubmitted.
The engine evaluates several conditions to determine whether a file can be accepted. Some conditions are influenced by system state, such as memory usage or processing load, while others, such as concurrency, are driven by the volume of incoming requests. Logging occurs when any of these conditions change, regardless of file submission activity.
Memory Usage
The system can optionally track memory usage and compare it to a configured threshold (processing-unavailable-at-memory-percent
). When enabled, memory usage is calculated as a percentage of either:
- the memory limit defined for the container (if set), or
- the total available system memory (if no container limit is present).
If this threshold is exceeded at the time of file submission, the application will reject the file until memory usage drops below the limit.
If the temporary directory is configured as tmpfs
, it will be counted toward memory usage.
Because memory usage depends on the complexity and unpacking behavior of previously submitted files, it may remain elevated even after no new uploads occur. The system logs when it enters and exits high-memory conditions independently of file submissions.
If the threshold is not configured, memory usage is not tracked or logged, and file rejection based on memory use is disabled.
Concurrency Limit
The system enforces a limit on concurrent requests, defined by the concurrency-limit
setting. If the number of active concurrent requests exceeds this limit, new submissions are temporarily rejected.
The concurrency limit applies globally to all uploads, regardless of whether they are routed to the regular core pool or cores reserved for large files.
Even if the concurrency limit is set to 0
(unlimited), the system still tracks the number of active concurrent requests.
Concurrency is controlled by the number of active file submissions at any given moment. This value is directly influenced by the client's submission behavior, making it a more predictable limit compared to memory or processing-based conditions.
Multiple Cores
Requests are assigned to Spectra Core instances. Each file is always processed by a single instance.
- All instances are identical in capability.
- You can configure a subset of instances to be reserved for files larger than the size threshold (
--large-file-threshold
). - Large-file instances process only one file at a time, regardless of the global concurrency limit.
- If no large instances are configured, all files are handled by the same pool.
The /readyz
endpoint returns 200 OK
if at least one instance (regular or large-file) is available.
For detailed availability per group, use the /status
endpoint.
Logging
If a file upload is rejected due to memory or processing conditions, the application will return the HTTP status 429 Too Many Requests
.
The application logs when it enters and exits high-load or high-memory states. These log entries are independent of file submission attempts, since resource usage is influenced by the complexity of previously submitted files, not just their size or frequency.
Log Examples
Processing Load: High and Normal
When a Spectra Core instance becomes busy, logs indicate that it cannot accept new files:
{
"level": "info",
"process": "fie",
"instance_id": "core-large-0.8qczl",
"time": "2025-09-24T15:39:07.618375188+02:00",
"message": "Instance is not ready"
}
{
"level": "warn",
"process": "core",
"instance_id": "core-large-0.8qczl",
"time": "2025-09-24T15:39:58.946518488+02:00",
"message": "High processing load"
}
When the load subsides and the instance can accept new files again, logs show a return to normal:
{
"level": "info",
"process": "core",
"instance_id": "core-large-0.8qczl",
"time": "2025-09-24T15:40:15.592637095+02:00",
"message": "High processing load over"
}
{
"level": "info",
"process": "fie",
"instance_id": "core-large-0.8qczl",
"time": "2025-09-24T15:40:15.677907694+02:00",
"message": "Instance is ready"
}
-
Instance is not ready
– The instance cannot accept new files right now. The/status
endpoint will show it as unavailable, and new submissions will be rejected until it becomes free again. -
High processing load
– The instance is busy. This is an additional signal but less important for deciding whether to submit new files. -
High processing load over
– The instance has returned to a normal state. -
Instance is ready
– The instance is available again, either because load subsided or after a restart.
If an instance recovers due to a timeout and restart, the return-to-normal sequence is slightly different: only the Instance is ready
message appears after the restart.
Memory Usage: High and Normal
{
"level": "warn",
"process": "fie",
"component": "readiness.Controller",
"time": "2025-09-24T13:55:38.184606708Z",
"message": "Memory use is above the threshold of 90%"
}
{
"level": "info",
"process": "fie",
"component": "readiness.Controller",
"time": "2025-09-24T13:56:33.183810287Z",
"message": "Memory use is below the threshold of 90%"
}
Timeouts
The engine enforces a configurable timeout for file analysis.
If a file exceeds the configured timeout:
- The Spectra Core instance handling the file is terminated and restarted.
- Any other analyses running on that instance are aborted.
- Logs will show that the analysis was aborted and timed out.
- The instance will need to restart and become ready again before it can accept new files. This usually takes a few seconds, but the exact time depends on system load and disk speed. For this reason, very short timeout values are not recommended.
{
"level": "warn",
"process": "fie",
"request_id": "3dc57796-2964-4249-bff3-c98ddef747ca",
"component": "scanner",
"sample_size": 86271956,
"sample_sha1": "0aa2f850f0e87ef84743f518a10d17e3b03395d7",
"sample_type": "application/x-unix-archive",
"scan_duration_ms": 60000.502133,
"analyzed_files": 0,
"timeout": "1m0s",
"time": "2025-09-23T17:35:57.299468984+02:00",
"message": "Analysis aborted due to a timeout"
}
{
"level": "warn",
"process": "fie",
"request_id": "3dc57796-2964-4249-bff3-c98ddef747ca",
"component": "http.api",
"request_path": "/scan",
"content_length": 86271956,
"scan_duration_ms": 60349.621584,
"sample_sha1": "0aa2f850f0e87ef84743f518a10d17e3b03395d7",
"time": "2025-09-23T17:35:57.307513847+02:00",
"message": "Analysis has timed out"
}
After a timeout, the affected instance restarts. Once recovery is complete, it logs that it is ready again:
{
"level": "info",
"process": "fie",
"instance_id": "core-regular-0.pwcpx",
"time": "2025-09-23T17:36:07.943715309+02:00",
"message": "Instance is ready"
}
The random suffix in the instance_id
changes after a restart.
Check Application Liveness
curl http://<host>:<port>/livez
Returns 200 OK
if the application process is running. Use for Kubernetes liveness probes.
Check Application Readiness
curl http://<host>:<port>/readyz
Returns 200 OK
only if:
-
The engine has fully initialized (including license validation) and is not too busy to process samples.
-
Current resource utilization is within configured limits (memory, concurrency) and the system is not too busy (Spectra Core, CPU/load) to process samples.
-
If not ready, returns a
4xx
or5xx
status.
Check Application Version / License / Configuration
GET /status
To check the File Inspection Engine version, license expiration date, threat data timestamp, and configuration, use the /status
endpoint.
The config
section contains all the configurable options and their current values. Values containing sensitive information are redacted.
The spectra_core
object describes how analysis instances are configured and available:
- percentage_of_regular_cores: The number of regular instances expressed as a percentage of the total CPU requests.
- If no large-file pool is configured (
--number-of-large-cores=0
), these instances handle all files. - Otherwise, they handle files up to the
--large-file-threshold
.
- If no large-file pool is configured (
- percentage_of_large_cores: The number of large-file instances expressed as a percentage of the total CPU requests.
- available_regular_cores / available_large_cores: Current availability of instances in each pool (available / total).
- total_cpus: The total number of CPUs used for calculating percentages. If
RL_CPU_REQUEST
is set, this value comes from that variable. Otherwise, it reflects the total CPUs detected on the node.
The percentage_*
fields compare instance counts to the CPU request value. They do not represent actual CPU allocation. Each instance may use more or fewer CPUs depending on workload and system limits.
curl http://<host>:<port>/status
{
"config": {
"add_file_type": "disabled",
"cloud_update_interval": "5m0s",
"cloud_updates": true,
"concurrency_limit": 20,
"cpu_request": 8,
"http_address": ":8000",
"large_file_threshold": 10,
"log_json": true,
"max_decompression_factor": 1,
"max_upload_file_size": 100,
"number_of_large_cores": 2,
"number_of_regular_cores": 4,
"paranoid_mode": false,
"processing_unavailable_at_memory_percent": 0,
"proxy_address": "http://user:xxxxx@proxy.company.lan",
"timeout": "0s",
"unpacking_depth": 17,
"with_threat_details": false
},
"license": {
"valid_until": "2025-12-01"
},
"spectra_core": {
"available_large_cores": "100% (2/2)",
"available_regular_cores": "100% (4/4)",
"percentage_of_large_cores": "25% (2)",
"percentage_of_regular_cores": "50% (4)",
"total_cpus": 8
},
"version": {
"application": "2.0.0",
"threat_data": "2025-09-24T11:26:10Z"
}
}