Pre-installation verification of VS Code extensions via URL — fetch a remote VSIX, extract it in a hardened sandbox, and run the existing IDE scanner pipeline against it. No npm dependencies. Sources: - VS Code Marketplace (publisher.gallery.vsassets.io direct download) - OpenVSX (open-vsx.org official API) - Direct .vsix HTTPS URLs Defenses: - HTTPS-only, TLS verified, manual redirect with per-source host whitelist - 30s total timeout via AbortController - 50MB compressed cap, 500MB uncompressed, 100x expansion ratio - Zero-dep ZIP extractor: zip-slip, absolute paths, drive letters, NUL bytes, symlinks (Unix mode 0xA000), depth limits, ZIP64 rejected, encrypted rejected - SHA-256 streamed during fetch, surfaced in meta.source - Temp dir cleanup in all paths (try/finally) Files: - scanners/lib/vsix-fetch.mjs (HTTPS fetcher, host whitelist, streaming SHA-256) - scanners/lib/zip-extract.mjs (zero-dep parser with hardening caps) - knowledge/marketplace-api-notes.md (endpoint reference) - 3 test files (48 tests added: vsix-fetch, zip-extract, ide-extension-url) Tests: 1296 → 1344 (all green). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
3.1 KiB
3.1 KiB
VS Code Marketplace + OpenVSX API notes
Reference notes for scanners/lib/vsix-fetch.mjs. These endpoints are used to
download VSIX packages for /security ide-scan <url> (v6.4.0).
VS Code Marketplace
Status: Undocumented but stable. Used by the vsce CLI and by VS Code itself.
Direct VSIX download (the URL we use)
https://{publisher}.gallery.vsassets.io/_apis/public/gallery/publisher/{publisher}/extension/{name}/latest/assetbyname/Microsoft.VisualStudio.Services.VSIXPackage
{publisher}and{name}come from theitemName=publisher.namequery parameter onhttps://marketplace.visualstudio.com/items.latestresolves to the most recent stable version. Specific versions can be requested by replacinglatestwith<version>.- The response is a ZIP (VSIX) with
Content-Type: application/octet-stream. - May redirect to
*.gallerycdn.vsassets.io. Our fetcher allows redirects only to that host family, never to arbitrary hosts.
extensionquery (not used here, listed for completeness)
POST https://marketplace.visualstudio.com/_apis/public/gallery/extensionquery
Headers:
Accept: application/json;api-version=3.0-preview.1
Content-Type: application/json
Body:
{ "filters": [{ "criteria": [{ "filterType": 7, "value": "publisher.name" }] }],
"flags": 914 }
This returns metadata (versions, publisher info, statistics) but is heavier than the direct download, and parsing the response shape is brittle. We keep the direct download path for v6.4.0.
Stability risk
Microsoft has changed Marketplace APIs in the past without warning. Mitigation:
- Fall back to OpenVSX when both options exist (most extensions are mirrored).
- Document the endpoint here so that breakage can be diagnosed quickly.
- All callers receive a single
Errorwith a descriptive message — no stack traces leak through to the scanner envelope.
OpenVSX (Eclipse Foundation)
Status: Officially documented at https://open-vsx.org/swagger-ui.
Resolve "latest" version
GET https://open-vsx.org/api/{publisher}/{name}/latest
Returns JSON. We extract .version and use it for the next request.
Direct VSIX download
GET https://open-vsx.org/api/{publisher}/{name}/{version}/file/{publisher}.{name}-{version}.vsix
Returns the raw VSIX. May redirect to openvsxorg.blob.core.windows.net.
Caps & defenses (shared by all sources)
- TLS verification enabled (no
--insecureopt-in). - HTTPS only. Plain HTTP is rejected at
detectUrlTypeand at fetch time. - Manual redirect handling. Allowed hosts whitelisted per source type.
- 30-second total timeout via
AbortController. - 50MB compressed VSIX cap. Streaming reader aborts when cap exceeded.
- SHA-256 computed during streaming for
meta.source.sha256.
What is NOT supported (v6.4.0)
- GitHub repo URLs — would need
npm install+vsce packagebuild step. - VS Code
code:protocol URIs. - VSIX signature verification (
.signature.p7s). Deferred to v6.5.0. - ZIP64 archives. Real VSIX never approaches the 4 GB threshold.
- Encrypted ZIP entries (general-purpose flag bit 0).