Skip to content

Archive and Upload Security

Elman Mohammadi edited this page Oct 6, 2026 · 1 revision

Archive and Upload Security

Before V14 package creation begins, the server may process an incoming ZIP source archive. This phase is separate from the V14 package format and has its own security controls.

Why a separate archive boundary exists

An incoming ZIP is untrusted data. It can contain:

  • directory traversal paths
  • Windows drive paths
  • duplicate output paths
  • symbolic links
  • huge declared sizes
  • deep directory structures
  • nested archives
  • encrypted entries

The archive layer therefore validates the ZIP before its contents become V14 source material.

Resumable uploads

The main API uses ResumableUploadStore.

The workflow is:

upload-init
    -> upload identifier
    -> upload-chunk (repeated)
    -> upload-complete
    -> optional SHA-256 verification
    -> archive job

Each upload is bound to the current owner identity through a hashed owner identifier.

Chunks are accepted at explicit offsets and protected by an upload lock so concurrent requests cannot safely race the state machine into an inconsistent position.

Upload configuration

The current application configuration includes:

  • maximum upload size: 1 TiB
  • maximum upload chunk: 8 MiB
  • upload TTL: 7200 seconds

These values are application transport policies and are distinct from V14 format limits.

Upload checksum

The upload initialization request may include a declared SHA-256 digest.

After all bytes are received, the server hashes the completed upload and compares the actual digest with the declared value before finalization.

ZIP path policy

Archive paths are normalized to / and rejected when they are:

  • absolute
  • Windows drive paths
  • empty or malformed
  • containing ..
  • containing . segments where disallowed
  • containing null/control characters
  • containing : in unsafe contexts
  • ending in a space or dot
  • using Windows reserved device names
  • longer than the configured path boundary

Symbolic links are not supported.

ZIP resource limits

The current application policy includes:

Limit Configured value
Archive entries 100,000
Single extracted file 16 GiB
Total uncompressed input 100 GiB
Archive depth 8
Nested archive count 64
Upload chunk 8 MiB
Total upload 1 TiB

The values above are the application configuration. The archive implementation also checks actual bytes streamed during extraction instead of relying only on metadata declared by a ZIP entry.

Nested archives

When an extracted file appears to be a ZIP, it may be queued for another archive-processing step, subject to the nested archive limit.

Nested archive outputs are redirected into controlled destination locations rather than being allowed to choose arbitrary filesystem paths.

Staging

Each archive step uses a temporary staging directory.

Files are extracted into staging first and merged into the job's source tree only after the step has passed validation.

This reduces the blast radius of a failed archive operation.

Duplicate paths

The archive layer rejects duplicate output paths and file/directory conflicts.

This matters because different ZIP tools or filesystems can interpret names differently, especially when case handling or normalization differs.

Failed archive password attempts

Archive passwords are rate-limited per job/archive/owner context. The default global rate-limit policy is 12 failures per 900-second window.

Why actual streamed byte counts matter

Declared ZIP entry sizes can be untrustworthy. The extraction code therefore tracks the number of bytes actually copied from the archive stream and enforces the configured total ceiling during the copy itself.

This is a resource-safety control against decompression/expansion abuse.

Portable .spkg14 archive safety

After the V14 package directory is built, PackageArchive creates the final .spkg14 ZIP.

When a .spkg14 package is opened later, the archive layer performs its own validation before the extracted directory is handed to V14PackageReader.

This two-stage architecture is intentional:

ZIP container safety != V14 package safety

Both need to pass.

Clone this wiki locally