diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index a09356b..95a4ec4 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -57,6 +57,9 @@ jobs: - name: Install server dependencies run: bun install --frozen-lockfile + - name: Typecheck server + run: bun run typecheck + - name: Run server tests run: bun run test diff --git a/ACCEPTABLE_USE.md b/ACCEPTABLE_USE.md new file mode 100644 index 0000000..0819ac7 --- /dev/null +++ b/ACCEPTABLE_USE.md @@ -0,0 +1,73 @@ +# Acceptable Use Policy + +Overlord is intended for lawful administration, support, testing, and +management of systems whose owners have given informed authorization. + +By using or distributing this project, you are responsible for complying with +applicable law, contractual obligations, organizational policy, and the terms +of every network and service involved. + +## Authorized use + +You may use Overlord for purposes such as: + +- Managing devices you own or are explicitly authorized to administer. +- Providing remote support with the device owner's or organization's consent. +- Operating an approved enterprise, laboratory, classroom, or homelab + environment. +- Conducting a documented security assessment within its agreed scope. +- Developing and testing defensive controls in an isolated environment. + +Authorization should identify the systems, accounts, operators, capabilities, +data-handling rules, and time period in scope. An accessible device is not +necessarily an authorized device. + +## Prohibited use + +Do not use Overlord to: + +- Access, monitor, control, enroll, or persist on a system without explicit + authorization. +- Collect credentials, keystrokes, audio, video, files, communications, or + personal data without a lawful purpose and appropriate consent. +- Conceal activity from a system owner or bypass required security, + privacy, monitoring, or consent controls. +- Deploy malware, ransomware, destructive payloads, or unauthorized + cryptomining. +- Exfiltrate, sell, publish, or misuse confidential or personal information. +- Disrupt services, damage systems, interfere with other users, or evade + incident response. +- Violate sanctions, export restrictions, intellectual-property rights, or + third-party service terms. +- Help another person perform any prohibited activity. + +## Operator responsibilities + +Operators must: + +- Use individual accounts and least-privilege permissions. +- Restrict agent enrollment and promptly revoke unauthorized or retired + clients. +- Protect credentials, signing material, tokens, recordings, logs, and + transferred files. +- Notify affected users and obtain consent where required. +- Configure appropriate retention and securely delete data when it is no + longer needed. +- Maintain audit records sufficient to attribute administrative actions. +- Stop testing when it creates unexpected risk or exceeds the approved scope. + +## Plugins and modifications + +Plugins, custom builds, scripts, and downstream modifications remain subject +to this policy. Their authors and operators are responsible for reviewing the +additional permissions, data access, network behavior, and security impact +they introduce. + +## Reporting misuse + +Report project security vulnerabilities according to +[SECURITY.md](SECURITY.md). For suspected misuse, preserve relevant +non-sensitive evidence and contact the service operator or appropriate +authority. Do not publish credentials, tokens, personal data, or exploit +details in a public issue. + diff --git a/Overlord-Server/bun.lock b/Overlord-Server/bun.lock index c947973..78c58d3 100644 --- a/Overlord-Server/bun.lock +++ b/Overlord-Server/bun.lock @@ -30,6 +30,7 @@ "@tailwindcss/cli": "^4.1.18", "@types/bun": "^1.3.9", "@types/geoip-lite": "latest", + "@types/node": "latest", "@types/uuid": "^9.0.7", "@xterm/addon-fit": "^0.11.0", "@xterm/addon-web-links": "^0.12.0", @@ -181,7 +182,7 @@ "@types/geoip-lite": ["@types/geoip-lite@1.4.4", "", {}, "sha512-2uVfn+C6bX/H356H6mjxsWUA5u8LO8dJgSBIRO/NFlpMe4DESzacutD/rKYrTDKm1Ugv78b4Wz1KvpHrlv3jSw=="], - "@types/node": ["@types/node@12.20.55", "", {}, "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ=="], + "@types/node": ["@types/node@26.1.2", "", { "dependencies": { "undici-types": "~8.3.0" } }, "sha512-Vu4a5UFA9rIIFJ7rB/Vaafh9lrCQszopTCx6KjFboXTGQbPNasehVR5TEiithSDGyd1DEiUByggTZsg8jukeIg=="], "@types/triple-beam": ["@types/triple-beam@1.3.5", "", {}, "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw=="], @@ -543,6 +544,8 @@ "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], + "undici-types": ["undici-types@8.3.0", "", {}, "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ=="], + "update-browserslist-db": ["update-browserslist-db@1.2.3", "", { "dependencies": { "escalade": "^3.2.0", "picocolors": "^1.1.1" }, "peerDependencies": { "browserslist": ">= 4.21.0" }, "bin": { "update-browserslist-db": "cli.js" } }, "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w=="], "utf-8-validate": ["utf-8-validate@6.0.6", "", { "dependencies": { "node-gyp-build": "^4.3.0" } }, "sha512-q3l3P9UtEEiAHcsgsqTgf9PPjctrDWoIXW3NpOHFdRDbLvu4DLIcxHangJ4RLrWkBcKjmcs/6NkerI8T/rE4LA=="], @@ -591,14 +594,22 @@ "@tailwindcss/oxide-wasm32-wasi/tslib": ["tslib@2.8.1", "", { "bundled": true }, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], + "@types/connect/@types/node": ["@types/node@12.20.55", "", {}, "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ=="], + + "@types/ws/@types/node": ["@types/node@12.20.55", "", {}, "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ=="], + "ansi-to-html/entities": ["entities@2.2.0", "", {}, "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A=="], "asn1.js/bn.js": ["bn.js@4.12.3", "", {}, "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g=="], + "bun-types/@types/node": ["@types/node@12.20.55", "", {}, "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ=="], + "color/color-convert": ["color-convert@3.1.3", "", { "dependencies": { "color-name": "^2.0.0" } }, "sha512-fasDH2ont2GqF5HpyO4w0+BcewlhHEZOFn9c1ckZdHpJ56Qb7MHhH/IcJZbBGgvdtwdwNbLvxiBEdg336iA9Sg=="], "color-string/color-name": ["color-name@2.1.0", "", {}, "sha512-1bPaDNFm0axzE4MEAzKPuqKWeRaT43U/hyxKPBdqTfmPF+d6n7FSoTFxLVULUJOmiLp01KjhIPPH+HrXZJN4Rg=="], + "jayson/@types/node": ["@types/node@12.20.55", "", {}, "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ=="], + "jayson/commander": ["commander@2.20.3", "", {}, "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="], "jayson/uuid": ["uuid@8.3.2", "", { "bin": { "uuid": "dist/bin/uuid" } }, "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="], @@ -614,5 +625,7 @@ "terser/commander": ["commander@2.20.3", "", {}, "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="], "color/color-convert/color-name": ["color-name@2.1.0", "", {}, "sha512-1bPaDNFm0axzE4MEAzKPuqKWeRaT43U/hyxKPBdqTfmPF+d6n7FSoTFxLVULUJOmiLp01KjhIPPH+HrXZJN4Rg=="], + + "rpc-websockets/@types/ws/@types/node": ["@types/node@12.20.55", "", {}, "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ=="], } } diff --git a/Overlord-Server/package.json b/Overlord-Server/package.json index de03e8b..34d1d13 100644 --- a/Overlord-Server/package.json +++ b/Overlord-Server/package.json @@ -48,6 +48,7 @@ "@tailwindcss/cli": "^4.1.18", "@types/bun": "^1.3.9", "@types/geoip-lite": "latest", + "@types/node": "latest", "@types/uuid": "^9.0.7", "@xterm/addon-fit": "^0.11.0", "@xterm/addon-web-links": "^0.12.0", diff --git a/Overlord-Server/src/server/macos-sdk-manager.ts b/Overlord-Server/src/server/macos-sdk-manager.ts index 7fd9fe6..4d670f1 100644 --- a/Overlord-Server/src/server/macos-sdk-manager.ts +++ b/Overlord-Server/src/server/macos-sdk-manager.ts @@ -43,7 +43,7 @@ export function purgeExpiredMacosSdkUploads(now = Date.now()): void { const dir = path.join(root, entry.name); const metadata = readMetadata(dir); if (!metadata || (!metadata.claimed && now - metadata.createdAt > UPLOAD_TTL_MS)) { - try { fs.rmdirSync(dir, { recursive: true }); } catch {} + try { fs.rmSync(dir, { recursive: true, force: true }); } catch {} } } } @@ -83,7 +83,7 @@ export async function stageMacosSdkUpload(req: Request, userId: number): Promise return metadata; } catch (error) { writer.destroy(); - try { fs.rmdirSync(dir, { recursive: true }); } catch {} + try { fs.rmSync(dir, { recursive: true, force: true }); } catch {} throw error; } } @@ -96,7 +96,7 @@ export function claimMacosSdkUpload(id: unknown, userId: number): ClaimedMacosSd throw new Error("macOS SDK upload was not found, expired, or has already been used"); } if (Date.now() - metadata.createdAt > UPLOAD_TTL_MS) { - try { fs.rmdirSync(dir, { recursive: true }); } catch {} + try { fs.rmSync(dir, { recursive: true, force: true }); } catch {} throw new Error("macOS SDK upload expired; please upload it again"); } metadata.claimed = true; @@ -179,5 +179,5 @@ export function cleanupMacosSdkUpload(uploadDir: string | undefined): void { const resolved = path.resolve(uploadDir); const root = path.resolve(uploadRoot()); if (path.dirname(resolved) !== root) return; - try { fs.rmdirSync(resolved, { recursive: true }); } catch {} + try { fs.rmSync(resolved, { recursive: true, force: true }); } catch {} } diff --git a/Overlord-Server/tsconfig.json b/Overlord-Server/tsconfig.json index 739460a..03a8e0d 100644 --- a/Overlord-Server/tsconfig.json +++ b/Overlord-Server/tsconfig.json @@ -8,7 +8,7 @@ "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "skipLibCheck": true, - "types": ["bun"], + "types": ["bun", "node"], "baseUrl": "./src" }, "include": ["src/**/*"] diff --git a/README.md b/README.md index 89474b5..cc06ce6 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,12 @@ The server is TypeScript on Node/Bun. The client is Go. Operators talk to the se Docker is the easiest way to run it. +> [!IMPORTANT] +> Use Overlord only on systems you own or are explicitly authorized to +> administer. Review the [Acceptable Use Policy](ACCEPTABLE_USE.md) before +> deployment. Report vulnerabilities privately according to the +> [Security Policy](SECURITY.md). + --- - [Quick Start (Docker)](#quick-start-docker) diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..c4489d3 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,90 @@ +# Security Policy + +## Supported versions + +Security fixes are developed for the latest released version and the `main` +branch. Older releases may not receive backported fixes. Before reporting a +problem, reproduce it against the latest release when it is safe to do so. + +## Reporting a vulnerability + +Do not disclose suspected vulnerabilities in a public issue, discussion, +chat, or pull request. + +Use the repository's private **Security advisory** reporting flow: + +1. Open the repository's **Security** tab. +2. Select **Advisories** and **Report a vulnerability**. +3. Include the affected version or commit, deployment configuration, impact, + reproduction steps, and any suggested mitigation. + +If private vulnerability reporting is unavailable, contact a maintainer +privately through a contact channel published by the project and ask for a +secure reporting method. Do not send exploit details until a private channel +has been established. + +Reports should contain: + +- A concise description of the issue and its security impact. +- The affected server, agent, desktop, plugin, or deployment component. +- Preconditions such as authentication level, network access, or platform. +- Minimal reproduction steps or a proof of concept. +- Relevant logs with credentials, tokens, client data, and personal data + removed. +- Whether the issue is known to be actively exploited or publicly disclosed. + +Maintainers will make a best effort to acknowledge a complete report within +three business days, validate and triage it, coordinate a remediation and +release, and credit the reporter unless anonymity is requested. + +## Disclosure expectations + +Please allow maintainers a reasonable opportunity to investigate and publish +a fix before public disclosure. Maintainers will communicate material changes +in severity or remediation status through the private report. + +Testing must follow [ACCEPTABLE_USE.md](ACCEPTABLE_USE.md). In particular, only +test systems and accounts you own or are explicitly authorized to assess. +Avoid accessing real user data, degrading service, establishing persistence, +or retaining data obtained during testing. + +## Operational security + +Operators are responsible for securing their deployment. At minimum: + +- Restrict network exposure and place internet-facing installations behind a + properly configured TLS endpoint. +- Change or otherwise protect default credentials before exposing the service + to untrusted networks. +- Protect `save.json`, databases, certificates, signing keys, agent tokens, + backups, and uploaded files as secrets. +- Enable agent authentication, enrollment approval, least-privilege RBAC, MFA, + and audit logging where appropriate. +- Keep the server, agents, desktop application, container images, host + operating system, and reverse proxy current. +- Review plugins and signing keys before installation. +- Back up persistent data and periodically test restoration. + +## Scope + +The following are generally in scope when they affect the latest release: + +- Authentication, authorization, session, MFA, OIDC, and enrollment bypasses. +- Cross-tenant or cross-client access. +- Remote code execution or command injection. +- Path traversal, unsafe upload handling, or unauthorized file access. +- Cryptographic, signing, update, or agent identity failures. +- Plugin sandbox escapes or signature-validation bypasses. +- Sensitive information exposure. + +The following are generally not security vulnerabilities by themselves: + +- Findings that require an already fully privileged administrator and do not + cross an intended trust boundary. +- Missing hardening on an installation that contradicts the documented + deployment requirements. +- Denial-of-service reports without a practical, reproducible impact. +- Automated scanner output without validation. +- Social engineering, physical attacks, or attacks against third-party + services outside the project's control. +