{"record":{"id":"14fbf1c9fb4b1254","repo":"vercel-labs/skills","slug":"archive-exceeds-maximum-unpacked-size","errorCode":null,"errorMessage":"Archive exceeds maximum unpacked size","messagePattern":"Archive exceeds maximum unpacked size","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/providers/wellknown.ts","lineNumber":707,"sourceCode":"    const parts = rawPath.split('/').filter(Boolean);\n    if (parts.length === 0) return null;\n    if (parts.some((part) => part === '.' || part === '..')) return null;\n\n    return parts.join('/');\n  }\n\n  private addArchiveFile(\n    files: Map<string, WellKnownFileContent>,\n    path: string,\n    content: Uint8Array,\n    runningTotal: { bytes: number }\n  ) {\n    const normalizedPath = this.normalizeArchivePath(path);\n    if (!normalizedPath) throw new Error(`Unsafe archive path: ${path}`);\n\n    runningTotal.bytes += content.byteLength;\n    if (runningTotal.bytes > MAX_ARCHIVE_UNPACKED_BYTES) {\n      throw new Error('Archive exceeds maximum unpacked size');\n    }\n    if (files.size >= MAX_ARCHIVE_FILES) {\n      throw new Error('Archive contains too many files');\n    }\n\n    files.set(normalizedPath, content);\n  }\n\n  private extractTarGz(bytes: Uint8Array): Map<string, WellKnownFileContent> {\n    const tar = gunzipSync(Buffer.from(bytes));\n    const files = new Map<string, WellKnownFileContent>();\n    const runningTotal = { bytes: 0 };\n    let offset = 0;\n\n    while (offset + 512 <= tar.length) {\n      const header = tar.subarray(offset, offset + 512);\n      if (header.every((byte) => byte === 0)) break;\n","sourceCodeStart":689,"sourceCodeEnd":725,"githubUrl":"https://github.com/vercel-labs/skills/blob/435076e78988e1e6ec40d00b0b1d76bdbbc5419a/src/providers/wellknown.ts#L689-L725","documentation":"The well-known provider caps archive extraction at MAX_ARCHIVE_UNPACKED bytes (a zip-bomb defense). addArchiveFile accumulates content.byteLength into runningTotal.bytes and throws as soon as the cumulative unpacked size exceeds the cap.","triggerScenarios":"A registry artifact whose cumulative extracted byte size crosses MAX_ARCHIVE_UNPACKED_BYTES — either a legitimately huge skill (bundled models/datasets) or a decompression bomb whose small .tar.gz expands enormously.","commonSituations":"Skills shipping large binary assets; malicious zip bombs served from a compromised registry; highly compressible placeholder files padding an archive.","solutions":["If the skill legitimately needs large assets, split them out and download lazily instead of bundling in the archive","Check the archive's unpacked size locally: tar -tzvf artifact.tar.gz (sizes shown)","Do not raise/disable the limit — it protects the process from OOM/disk exhaustion","Re-publish a slimmed artifact containing only SKILL.md plus small refs"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"const head = await fetch(artifactUrl, { method: 'HEAD' });\nconst packed = Number(head.headers.get('content-length') ?? 0);\n// gzip worst-case expansion ~1000x: refuse implausibly dense artifacts\nif (packed > 0 && packed < 1024 && artifactUrl.endsWith('.tar.gz')) {\n  logger.warn('suspicious compression ratio; may exceed unpacked limit');\n}","typeGuard":"function isUnpackedSizeExceeded(e: unknown): e is Error {\n  return e instanceof Error && /exceeds maximum unpacked size/i.test(e.message);\n}","tryCatchPattern":"try { await provider.fetchArtifact(url); }\ncatch (e) {\n  if (isUnpackedSizeExceeded(e)) {\n    logger.warn(`Artifact ${url} too large when unpacked; skipping`);\n    return null;\n  }\n  throw e;\n}","preventionTips":["Keep bundled artifacts small — assets belong behind URLs, not in archives","Check unpacked size (tar -tzvf) during CI packaging","Never attempt to raise the provider's unpacked-bytes cap"],"tags":["security","zip-bomb","limits","archive","wellknown-provider"],"backgroundTag":"archive-size-limit-exceeded","analyzedSha":"435076e78988e1e6ec40d00b0b1d76bdbbc5419a","analyzedAt":"2026-08-28T17:47:53.369Z","schemaVersion":2},"datasetVersion":"2026-08-28T21:17:43.275Z"}