# Terms of Service & Policy Compliance Audit Pack ## Scope This pack audits for terms-of-service, license, and platform-policy violations across five compliance surfaces: (1) OSS/dependency license compliance, (2) third-party API and service ToS, (3) app/extension store and platform policy, (4) AI/LLM provider ToS, and (5) any other relevant ToS surface (email/SMS consent, payment processors, OAuth scope, CDN licensing). This is a COMPLIANCE audit: findings flag legal/policy risk for human review. Most findings are NOT auto-fixable — they require human or legal judgment. The pack self-detects which policy regimes apply based on the project's manifest files and dependencies; it does NOT audit runtime security controls (covered by the security pack) or dependency CVEs (covered by the dependencies pack). **Pack ID:** `ccgm/tos-compliance` **Applies when:** `always` --- ## applies_when Rationale | Condition | Reason | |-----------|--------| | `always` | Every codebase has some applicable compliance surface — at minimum, its own declared license and any third-party dependencies it ships. The pack self-detects which of the five compliance surfaces are relevant based on project indicators (package.json, manifest.json, Info.plist, AI SDK imports, HTTP clients), so running on all repos produces zero false starts on non-applicable checks while ensuring no project escapes compliance review. | --- ## Checks --- ### `tos-compliance/copyleft-in-proprietary` **Severity:** `critical` **Confidence:** `high` **Detection:** `llm` #### Detection **LLM instruction (if detection = llm or hybrid):** ``` READ AND APPLY: ~/.claude/skills/audit/reference/fix-patterns.md Use the Fix Type Reference table from that file when assigning fix_type and fix_confidence. Do not rely on memory — open and apply the file. Surface (1): OSS / DEPENDENCY LICENSE COMPLIANCE First detect the project's own license (LICENSE file, package.json "license", "private": true). Then enumerate dependency licenses: npm: run `npx license-checker --summary` (or parse package-lock.json / node_modules/*/LICENSE) Python: run `pip-licenses` or parse site-packages metadata Go: inspect go.sum + vendor/ LICENSE files Rust: inspect Cargo.lock + crates.io metadata .NET: inspect *.csproj / NuGet PackageReference entries + nuget.org license metadata Identify dependencies carrying copyleft licenses that are LINKED INTO a proprietary or differently-licensed product: - GPL-2.0, GPL-3.0, LGPL-2.0, LGPL-2.1, LGPL-3.0 linked into a proprietary binary (dynamic linking may avoid LGPL copyleft but requires careful analysis) - AGPL-3.0 or SSPL used in a network-served or SaaS application (these trigger source-disclosure obligations for the entire service) - OSL-3.0, EUPL-1.2, CDDL in a proprietary product (copyleft scope varies) - Any copyleft license where the project's own license is incompatible (e.g. GPL-3.0 dep in a GPL-2.0-only project) Also check vendored/copied third-party source in vendor/ directories — shipped without its original license header triggers the same copyleft obligation. Also check fonts, icon sets, images, datasets, and ML model weights with restrictive licenses (e.g. "non-commercial research only" weights, icon sets requiring a paid commercial license, datasets forbidding commercial or redistribution use). OPTIONAL internet-powered confirmation (do not block on the network — fall back to offline pattern + metadata analysis if unavailable): - Resolve exact license: `npm view {package} license` or `WebFetch https://registry.npmjs.org/{package}` - Check for a relicense: `WebSearch: "{package} license change relicense BUSL"` For each finding: dependency name, its license, the project's license, why this is a copyleft violation, and a concrete remediation (replace with MIT/Apache alternative, obtain a commercial license, open-source the project). auto_fixable=false. ``` #### Spine Wiring ```yaml check_id: tos-compliance/copyleft-in-proprietary detection: llm ``` #### Severity / Confidence **Severity rationale:** AGPL/SSPL in a SaaS product or GPL linked into a proprietary binary obligates the entire product to be open-sourced. Non-compliance creates immediate legal liability and potential injunctions against distribution. CRITICAL per the ToS prompt severity guidance. **Confidence rationale:** License identifiers in package metadata are explicit strings — SPDX identifiers are deterministic. The primary ambiguity is in what constitutes "linking" for LGPL, but the check flags for human review rather than auto-fixing, reducing false-negative risk. HIGH confidence. **Rubric entry:** `tos-compliance/copyleft-in-proprietary` #### Fixture **True positive** (`package.json`): ```json { "private": true, "dependencies": { "some-agpl-lib": "1.0.0" } } ``` *(private/proprietary product shipping an AGPL-3.0 dependency — CRITICAL finding)* **True negative** (should produce NO finding): ```json { "license": "MIT", "dependencies": { "lodash": "4.17.21" } } ``` *(MIT project using MIT dependency — no copyleft conflict)* --- ### `tos-compliance/non-commercial-in-commercial` **Severity:** `critical` **Confidence:** `high` **Detection:** `llm` #### Detection **LLM instruction (if detection = llm or hybrid):** ``` READ AND APPLY: ~/.claude/skills/audit/reference/fix-patterns.md Use the Fix Type Reference table from that file when assigning fix_type and fix_confidence. Do not rely on memory — open and apply the file. Surface (1): OSS / DEPENDENCY LICENSE COMPLIANCE (non-commercial licenses) Enumerate dependency licenses (same enumeration as copyleft-in-proprietary check above). Identify dependencies carrying "non-commercial" or "source-available" licenses used in a commercial product: - CC-BY-NC-* (Creative Commons Non-Commercial) variants - BUSL-1.1 (Business Source License) — prohibits commercial production use until the Change Date (typically 4 years after release) - Elastic-2.0 / Elasticsearch license — prohibits competing SaaS offering - Commons Clause addendum — restricts selling the software as a service - Polyform Noncommercial 1.0.0 — non-commercial use only - "Source available" licenses that prohibit commercial use or competing products Determine if the project is commercial: - Presence of payment processor integrations (Stripe, PayPal, Braintree) - "private": true with a pricing or subscription model - SaaS indicators: multi-tenancy, user accounts with paid tiers For each finding: dependency name, its license, how the project uses it commercially, and remediation (switch to a commercially licensed alternative, negotiate a commercial license). auto_fixable=false. ``` #### Spine Wiring ```yaml check_id: tos-compliance/non-commercial-in-commercial detection: llm ``` #### Severity / Confidence **Severity rationale:** Using a non-commercial or "source-available" license in a commercial product constitutes license breach. CRITICAL because the licensor can demand immediate cessation and seek damages. **Confidence rationale:** License identifiers in metadata are explicit; determining whether a project is "commercial" from code signals (payment integrations, private flag, SaaS patterns) is reliable. HIGH confidence. **Rubric entry:** `tos-compliance/non-commercial-in-commercial` #### Fixture **True positive** (`package.json`): ```json { "private": true, "dependencies": { "elasticsearch": "8.0.0" } } ``` *(Elastic-2.0 licensed package used in a private commercial SaaS — CRITICAL finding)* **True negative** (should produce NO finding): ```json { "license": "MIT", "dependencies": { "express": "4.18.2" } } ``` *(MIT express in any product — no restriction)* --- ### `tos-compliance/missing-attribution` **Severity:** `high` **Confidence:** `medium` **Detection:** `llm` #### Detection **LLM instruction (if detection = llm or hybrid):** ``` READ AND APPLY: ~/.claude/skills/audit/reference/fix-patterns.md Use the Fix Type Reference table from that file when assigning fix_type and fix_confidence. Do not rely on memory — open and apply the file. Surface (1): OSS / DEPENDENCY LICENSE COMPLIANCE (attribution) MIT, BSD-2/3, Apache-2.0, and ISC licenses all require preserving the copyright notice and license text in distributions. Apache-2.0 additionally requires stating changes. Check for missing attribution in the following contexts: 1. Bundled frontends and browser extensions: look for a NOTICE, THIRD-PARTY-LICENSES, or LICENSES file in the build output directory (dist/, build/, extension build artifacts). If the project bundles dependencies (webpack, Rollup, Vite, esbuild) and the build output lacks such a file, flag it. 2. Shipped binaries: if the project compiles to an executable (Go, Rust, C++), check for a NOTICE or LICENSES file in the release bundle. 3. Copied/vendored source: any file in vendor/, third_party/, or a source directory that has been copied from another project needs its original copyright header preserved. 4. Apache-2.0 dependencies: if any Apache-2.0 dependency is shipped, a NOTICE file is required aggregating change notices. auto_fixable=true (low confidence) — generating a THIRD-PARTY-LICENSES file from dependency metadata is mechanically possible (npx generate-license-file, license-checker --out THIRD-PARTY-LICENSES --files, go-license-detector, etc.) but requires human review because the tool output may be incomplete or formatted incorrectly. The fix agent may generate the file as a starting point; it must be reviewed before commit. For each finding: the artifact type, what attribution is missing, and the tool to use for remediation (e.g. license-checker, generate-license-file, go-license-detector). ``` #### Spine Wiring ```yaml check_id: tos-compliance/missing-attribution detection: llm ``` #### Severity / Confidence **Severity rationale:** MIT/BSD/Apache licenses are permissive but attribution is a condition of use. Shipping a bundled artifact without attribution violates the license terms for every included dependency. HIGH because it's a legal obligation, though typically resolved without litigation. **Confidence rationale:** Whether a NOTICE/THIRD-PARTY-LICENSES file exists in the output directory is deterministic. The ambiguity is in whether all required packages are covered, yielding medium confidence. **Rubric entry:** `tos-compliance/missing-attribution` #### Fixture **True positive** (bundled extension without attribution): ``` dist/ background.js (bundles lodash, axios — both MIT requiring attribution) content.js # No THIRD-PARTY-LICENSES or NOTICE file present ``` *(FINDS: bundled dependencies without required attribution file)* **True negative** (should produce NO finding): ``` dist/ background.js THIRD-PARTY-LICENSES (contains copyright notices for all bundled deps) ``` *(Attribution file present — no finding)* --- ### `tos-compliance/unlicensed-dependency` **Severity:** `medium` **Confidence:** `high` **Detection:** `llm` #### Detection **LLM instruction (if detection = llm or hybrid):** ``` READ AND APPLY: ~/.claude/skills/audit/reference/fix-patterns.md Use the Fix Type Reference table from that file when assigning fix_type and fix_confidence. Do not rely on memory — open and apply the file. Surface (1): OSS / DEPENDENCY LICENSE COMPLIANCE (unlicensed/unknown) Enumerate dependency licenses (same enumeration as copyleft-in-proprietary check above). Identify dependencies where: - The license field is "UNLICENSED", undefined, or absent - The license is proprietary without a clear commercial license for the project's use case - The license is a custom string that is unrecognized (not a standard SPDX identifier) Also check for license incompatibilities between dependencies: - A GPL-3.0 dependency in a project that is GPL-2.0-only - A mix of strong copyleft licenses with conflicting viral clauses OPTIONAL internet check (do not block on the network — fall back to offline pattern + metadata analysis if unavailable): - `npm view {package} license` or `WebFetch https://registry.npmjs.org/{package}` to resolve unclear license metadata. For each finding: package name, its license metadata (or lack thereof), and why the obligation is unclear. Recommend resolving via the registry, the package's repository, or contacting the maintainer. auto_fixable=false. ``` #### Spine Wiring ```yaml check_id: tos-compliance/unlicensed-dependency detection: llm ``` #### Severity / Confidence **Severity rationale:** An unlicensed dependency carries unknown legal obligations — default copyright law applies, which means all rights are reserved by the author. Using it in a product could constitute infringement. MEDIUM because the risk is often theoretical for small/obscure packages; human review is needed. **Confidence rationale:** "UNLICENSED" as a metadata value is deterministic. Identifying custom/unknown SPDX strings requires pattern matching that is reliable. HIGH confidence. **Rubric entry:** `tos-compliance/unlicensed-dependency` #### Fixture **True positive** (`package.json`): ```json { "dependencies": { "internal-tool": "1.0.0" } } ``` *(Where internal-tool/package.json has `"license": "UNLICENSED"` — finding reported)* **True negative** (should produce NO finding): ```json { "dependencies": { "lodash": "4.17.21" } } ``` *(lodash is MIT — clearly licensed)* --- ### `tos-compliance/scraping-prohibited-site` **Severity:** `high` **Confidence:** `medium` **Detection:** `llm` #### Detection **LLM instruction (if detection = llm or hybrid):** ``` READ AND APPLY: ~/.claude/skills/audit/reference/fix-patterns.md Use the Fix Type Reference table from that file when assigning fix_type and fix_confidence. Do not rely on memory — open and apply the file. Surface (2): THIRD-PARTY API & SERVICE ToS — scraping and crawling Look for code that performs automated access to third-party sites whose ToS prohibit it: - HTTP clients (fetch, axios, got, requests, httpx, net/http) making requests to LinkedIn, Meta/Instagram/Facebook, X/Twitter, Amazon product pages, Google SERP (not the official Search API), Ticketmaster, or other sites known to prohibit scraping in their ToS - Headless browser automation (Playwright, Puppeteer, Selenium, Cypress) targeting third-party authenticated sites - Use of yt-dlp, youtube-dl, or similar download tools against protected content - Bulk crawling tools (Scrapy, Colly, crawler-based scripts) targeting third-party hosts - Code that deliberately ignores robots.txt or randomizes request timing to avoid detection Also check for: - Prohibited storage/caching of provider data: Google Maps/Places content stored beyond cache limits; market/financial data redistributed; geocoding results cached against the provider's ToS; social media posts stored beyond what the API terms permit. OPTIONAL internet check (do not block on the network — fall back to offline pattern + metadata analysis if unavailable): - `WebSearch: "{service} terms of service automated access prohibited"` - `WebFetch` the service's robots.txt or ToS page to confirm current policy For each finding: the target site/service, the specific code performing the access, the ToS clause being violated, and remediation (use the official API, obtain a data license, remove the scraping code). auto_fixable=false. ``` #### Spine Wiring ```yaml check_id: tos-compliance/scraping-prohibited-site detection: llm ``` #### Severity / Confidence **Severity rationale:** Scraping sites that prohibit it violates their ToS and may constitute unauthorized computer access. Major platforms enforce these terms actively. HIGH severity due to legal and service-disruption risk. **Confidence rationale:** Identifying HTTP clients targeting known prohibited domains is reliable, but determining intent (scraping vs. legitimate API calls) requires context. Medium confidence. **Rubric entry:** `tos-compliance/scraping-prohibited-site` #### Fixture **True positive** (`src/scraper.ts`): ```typescript // FINDS: fetching LinkedIn pages in a loop — prohibited by LinkedIn ToS for (const profileUrl of profileUrls) { const page = await fetch(profileUrl, { headers: { "User-Agent": randomUserAgent() } }); } ``` **True negative** (should produce NO finding): ```typescript // OK: using the official LinkedIn API with a valid access token const response = await fetch("https://api.linkedin.com/v2/me", { headers: { Authorization: `Bearer ${accessToken}` }, }); ``` --- ### `tos-compliance/credential-misuse` **Severity:** `high` **Confidence:** `medium` **Detection:** `llm` #### Detection **LLM instruction (if detection = llm or hybrid):** ``` READ AND APPLY: ~/.claude/skills/audit/reference/fix-patterns.md Use the Fix Type Reference table from that file when assigning fix_type and fix_confidence. Do not rely on memory — open and apply the file. Surface (2): THIRD-PARTY API & SERVICE ToS — credential misuse Look for patterns where API keys or credentials are used in violation of their terms: - A single API key (stored server-side or in env vars) being proxied to many users without individual user accounts — often violates the provider's "one account per user" policy - Free or personal-tier keys (trial/hobby plans) serving commercial or multi-tenant traffic that exceeds the tier's permitted use - API keys embedded in client-side JavaScript, mobile binaries, or extension bundles where they can be extracted by end users - Key rotation or credential pooling to circumvent per-key rate limits - Proxy layers that strip provider attribution (e.g. reselling an API without disclosure) For each finding: which credential is misused, how it is being shared or exposed, the provider's specific policy clause being violated, and remediation (migrate to per-user credentials, upgrade to commercial tier, move keys to server-side). auto_fixable=false. ``` #### Spine Wiring ```yaml check_id: tos-compliance/credential-misuse detection: llm ``` #### Severity / Confidence **Severity rationale:** Sharing a single API key across many users or using free-tier keys commercially violates provider agreements, can lead to account termination, and may cause unexpected charges to the key owner. HIGH severity. **Confidence rationale:** Client-side key embedding is detectable; identifying "proxied to many users" requires architectural inference. Medium confidence. **Rubric entry:** `tos-compliance/credential-misuse` #### Fixture **True positive** (`src/api-proxy.ts`): ```typescript // FINDS: personal free-tier OpenAI key hard-wired into commercial multi-tenant SaaS // (sk-proj-... key belongs to individual free-tier account, not an org/paid account) const openai = new OpenAI({ apiKey: "sk-proj-abc123freeTierPersonalKey", // free-tier personal key in commercial app }); const response = await openai.chat.completions.create({ model: "gpt-4o", messages: userMessages, // serving all paying customers through one personal free-tier key }); ``` **True negative** (should produce NO finding): ```typescript // OK: sanctioned pattern — org account platform key on the app backend serving all users // OpenAI permits this; "one key per user" is not required for server-side API usage const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY, // org/paid-tier platform key, server-side only }); const response = await openai.chat.completions.create({ model: "gpt-4o", messages: userMessages, }); ``` --- ### `tos-compliance/remote-code-extension` **Severity:** `critical` **Confidence:** `high` **Detection:** `llm` #### Detection **LLM instruction (if detection = llm or hybrid):** ``` READ AND APPLY: ~/.claude/skills/audit/reference/fix-patterns.md Use the Fix Type Reference table from that file when assigning fix_type and fix_confidence. Do not rely on memory — open and apply the file. Surface (3): APP / EXTENSION STORE & PLATFORM POLICY — remote code execution and hot-code-push This check covers two related prohibited patterns: A. Browser extension remote code (when manifest.json with "manifest_version" is detected): Scan the extension source for patterns prohibited by Manifest V3 and Chrome Web Store policy: - Fetching JavaScript, WebAssembly, or other executable code from a remote URL and executing it (fetch().then(eval), import() from a remote URL, dynamic script tag injection with a remote src, XMLHttpRequest to load code) - Use of eval(), new Function(), setTimeout(string), setInterval(string), or Function.prototype.constructor(string) with any argument that could originate from a remote source or user input - Obfuscated source code with no readable build: minified-only submissions without a corresponding human-readable source link are rejected by the Web Store - Dynamically generated content scripts or background scripts - WebSocket or SSE connections used to receive and execute code strings B. Mobile app hot-code-push / executable code download (when iOS/Android project indicators are detected — Info.plist, *.xcodeproj, Podfile, fastlane, AndroidManifest.xml, build.gradle): - OTA update mechanisms (CodePush, Expo OTA for native modules, JSPatch) that change app functionality beyond JS content without App Store review - Downloading and executing JS, bytecode, or native code from a CDN at runtime in ways that alter core app functionality (bypasses Apple's review requirement for code changes) - RCTBridge or equivalent hooks used to load remote native modules For each finding: the file and line, the specific remote-code or hot-code-push pattern, the applicable platform rule being violated (MV3 policy / Apple Review Guideline 2.5.2), and remediation (bundle all code, use a server API for data — not code execution; for iOS use only permitted JS update frameworks that do not change native behavior). auto_fixable=false. ``` #### Spine Wiring ```yaml check_id: tos-compliance/remote-code-extension detection: llm ``` #### Severity / Confidence **Severity rationale:** Remote code execution in a browser extension bypasses the Chrome Web Store review process, is explicitly prohibited by Manifest V3, and causes immediate store removal. Mobile app hot-code-push that changes native functionality bypasses App Store review and results in removal or rejection. Both patterns are CRITICAL per the ToS prompt severity guidance ("IAP-bypass or remote-code causing store rejection/removal" listed under CRITICAL). **Confidence rationale:** `eval()`, `new Function()`, and remote `