Safely Extract Archive
file.safe_extract_archive
Overview
You pass a managed ZIP reference and we extract entries into tenant-isolated managed storage with mandatory safety checks: we reject path traversal, absolute or drive-letter paths, NUL bytes, symlink entries (unless you opt in), entry-count caps, total uncompressed size caps, and per-entry compression-ratio limits. Each extracted file gets a new fileRef and SHA-256. Do not use this to write to arbitrary filesystem paths on your servers. Archive members cost 1 execution credit per 10 members, rounded up, minimum 1, capped at 10000 members (1000 credits).
Archive extraction is dangerous — we enforce the standard defenses by default so you do not reimplement them in every workflow.
Reliability
The same archive always extracts the same bytes, but the call is not idempotent: every run mints new file references, so a retry leaves you with a second copy to clean up or ignore. Safety checks abort the whole extraction rather than skipping an entry, and none of the typed failures improve on retry. ARCHIVE_MALFORMED means the bytes do not start with the PK signature or the ZIP could not be opened, so re-upload the file or reject it as corrupt. ARCHIVE_ENTRY_LIMIT_EXCEEDED means the archive holds more entries than maxEntries (10,000 by default, up to 1,000,000) — raise the cap if you trust the archive. ARCHIVE_UNCOMPRESSED_LIMIT_EXCEEDED means the extracted bytes passed maxTotalUncompressedBytes (500 MiB by default and as a hard platform maximum), or one file passed the 50 MiB managed-object maximum, so lower the archive size or split the bundle; caller values cannot raise either platform limit. ARCHIVE_COMPRESSION_RATIO_EXCEEDED means one entry expands by more than maxCompressionRatio (100 by default and as a hard platform maximum), measured from the bytes we actually expand rather than the ZIP's claimed size — treat the archive as hostile. ARCHIVE_UNSAFE_ENTRY_PATH means an entry path was empty, absolute, backslashed, carried .. or a drive letter, or contained a NUL byte, all of which would escape the destination, so reject the archive. ARCHIVE_SYMLINK_REJECTED means a symlink entry was present while allowSymlinks is false — opt in deliberately or drop the archive. Separately, an expired or foreign fileRef, an archive over 200 MiB, and an archiveType outside zip and auto come back as validation errors, and the fix is to re-upload or correct the field.
Context footprint
Returns per-file references, SHA-256 digests, and extraction summary statistics. Archive members cost 1 execution credit per 10 members, rounded up, minimum 1, capped at 10000 members (1000 credits). The archive reference does not name member count, so we reserve that ceiling, or a lower maxEntries when you supply one, until settlement reports the members actually extracted.
When to use it
To unpack an untrusted archive into isolated managed storage.
When you only need a manifest (use file.extract_zip_manifest).
Scope
Non-goals
- Does not extract to caller-controlled filesystem paths
- Does not follow symlinks by default
- Does not decrypt password-protected archives
Properties
Capabilities
Cost & billing
1 execution credit per 10 archive members, rounded up, reserved from the request and capped at 10000 members (1000 credits).
File handling
File limits
Constraints this skill applies to your input and generated files. The “Limited by” column shows the static source of each cap; none of these can be raised by upgrading your plan.
| Limit | Value | Limited by |
|---|---|---|
| Maximum size per input file | 50 MiB | Platform maximum |
| Max archive entries | 1,000,000 | Skill content limit |
How we handle your data
What this means
This skill may temporarily store files or intermediate data only to complete execution. Temporary data is protected and automatically deleted.
Squillify guarantees
- Runs inside Squillify
- This skill runs inside Squillify.
- Payloads are not sent to an external service by this skill.
- Temporary execution only storage
- Squillify does not permanently store submitted payloads.
- Telemetry records metadata only, not submitted content.
- Submitted payloads are not used for training.
- Submitted payloads are not reviewed by humans.
- This skill does not target sensitive data.
- The response may contain submitted or transformed content.
Your responsibility
Squillify does not determine whether submitted content is sensitive. Your application is responsible for deciding what data it is allowed to submit. Your application is responsible for securing the response.
Input schema
| Field | Type | Required | Description |
|---|---|---|---|
| fileRef | string | Yes | Managed ZIP reference resolved inside the current tenant, read up to 200 MiB. |
| archiveType | string | No | Archive kind; omit it for auto. |
| destinationPolicy | string | No | Extracted-file lifetime; omit it for managed_storage. |
| maxEntries | integer | No | How many entries are walked before failing; omit it for 10000. |
| maxTotalUncompressedBytes | integer | No | Ceiling on extracted bytes; omit it for 524288000, and larger values are clamped to that platform ceiling. |
| maxCompressionRatio | number | No | Largest allowed uncompressed-to-compressed ratio; omit it for 100. |
| allowSymlinks | boolean | No | Whether symlink entries are stored as ordinary files; omit it for false. |
Output schema
| Field | Type | Required | Description |
|---|---|---|---|
| ok | boolean | Yes | Always true on successful extraction. |
| files | array | Yes | Bounded array of 0 through 1000000 closed extracted files in archive order. |
| summary | object | Yes | Closed extraction totals including destination policy, extracted file count and skipped count. |
| metadata | object | No | Closed extraction metadata naming the entry cap, symlink detection, and engine. |
API contract
POST /v1/executecurl -sS -X POST "$BASE/v1/execute" -H "Authorization: Bearer $KEY" -H 'Content-Type: application/json' -d '{"skillKey":"file.safe_extract_archive","input":{"fileRef":"squillify://files/f-1"}}'import { Squillify } from "@squillify/sdk";
const sq = new Squillify({ apiKey: process.env.SQUILLIFY_API_KEY });
const { output } = await sq.execute("file.safe_extract_archive", {"fileRef":"squillify://files/f-1"});Errors
| Code | HTTP | Retryable | Description |
|---|---|---|---|
| VALIDATION_ERROR | 400 | No | The request payload failed schema validation. |
| UNAUTHORIZED | 401 | No | Missing or invalid API key. |
| SKILL_NOT_ACCESSIBLE | 403 | No | The API key is not granted access to this skill. |
| SKILL_NOT_AVAILABLE_FOR_PLAN | 403 | No | This skill is not included in your current plan. |
| PLAN_ELIGIBILITY_UNAVAILABLE | 503 | Yes | Plan eligibility could not be decided. Retry after backoff. |
| SKILL_NOT_FOUND | 404 | No | The requested skill or version does not exist. |
| TENANT_RATE_LIMITED | 429 | Yes | Request rate limit exceeded. Retry after backoff. |
| QUOTA_EXCEEDED | 429 | Yes | Plan quota exhausted. Retryable once the quota period resets. |
| EXECUTION_TIMEOUT | 504 | Yes | Execution exceeded the allowed time budget. |
| ARCHIVE_MALFORMED | 400 | No | The request payload failed this skill's input validation. |
| ARCHIVE_ENTRY_LIMIT_EXCEEDED | 429 | No | A size, quota, rate, or time limit was exceeded. |
| ARCHIVE_UNCOMPRESSED_LIMIT_EXCEEDED | 429 | No | A size, quota, rate, or time limit was exceeded. |
| ARCHIVE_COMPRESSION_RATIO_EXCEEDED | 429 | No | A size, quota, rate, or time limit was exceeded. |
| ARCHIVE_UNSAFE_ENTRY_PATH | 422 | No | The input was rejected as unsafe. |
| ARCHIVE_SYMLINK_REJECTED | 422 | No | The input was rejected as unsafe. |
Other limits
| Limit | Value |
|---|---|
| Recommended inline bytes | 32 KiB |
Limitations
- Does not extract to caller-controlled filesystem paths
- Does not follow symlinks by default
- Does not decrypt password-protected archives
- Inspect-only archive listing (use file.extract_zip_manifest)
- Writing extracted files to your local disk paths
How to call
POST /v1/execute (requires authentication)
{
"skillKey": "file.safe_extract_archive",
"input": {
"fileRef": "squillify://files/f-1"
}
}Examples
Extract a small text file from a ZIP
{
"fileRef": "squillify://files/f-1"
}{
"ok": true,
"summary": {
"totalUncompressedBytes": 5,
"extractedCount": 1,
"destinationPolicy": "managed_storage",
"directories": 0
},
"files": [
{
"expiresAt": "2026-07-13T00:10:00Z",
"sha256": "8ed3f6ad685b959ead7022518e1af76cd816f8e8ec7ccdda1ed4018e8f2223f8",
"path": "a.txt",
"fileRef": "squillify://files/f-out-1",
"sizeBytes": 5
}
],
"metadata": {
"engine": "commons-compress",
"symlinkDetection": "Unix external-attribute mode",
"maxEntries": 10000
}
}Short-lived temp storage for one-off processing
{
"fileRef": "squillify://files/f-1",
"destinationPolicy": "managed_temp"
}{
"ok": true,
"summary": {
"totalUncompressedBytes": 5,
"extractedCount": 1,
"destinationPolicy": "managed_temp",
"directories": 0
},
"files": [
{
"expiresAt": "2026-07-13T00:10:00Z",
"sha256": "8ed3f6ad685b959ead7022518e1af76cd816f8e8ec7ccdda1ed4018e8f2223f8",
"path": "a.txt",
"fileRef": "squillify://files/f-out-1",
"sizeBytes": 5
}
],
"metadata": {
"engine": "commons-compress",
"symlinkDetection": "Unix external-attribute mode",
"maxEntries": 10000
}
}Recommended use cases
- Ingest uploaded archives safely before downstream processing
- Unpack bundles into isolated managed file references
- Get per-file SHA-256 after controlled extraction
Avoid for
- Inspect-only archive listing (use file.extract_zip_manifest)
- Writing extracted files to your local disk paths
Related skills
Composable with
Safety & privacy
- Runs without calling any external service.
- Your payloads are never stored permanently.
- Telemetry captures metadata only — never your payload contents.
- We never train models on your payloads.
- No human reviews your payloads.