Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# CodeQL: static analysis for the whole tree (backend/ + frontend/).
#
# Both halves are interpreted TypeScript, so CodeQL's `build-mode: none`
# extracts them straight from source — no npm ci, no build step, and no
# autobuild guessing at the two-package layout. One analyze job covers
# backend and frontend together. The weekly cron re-runs analysis on an
# otherwise-quiet tree so newly shipped CodeQL queries still get applied.
# Findings land in the Security tab (code scanning), not as CI noise.
name: CodeQL

on:
push:
branches: [main]
pull_request:
branches: [main]
schedule:
# Mondays 04:30 UTC.
- cron: "30 4 * * 1"

permissions:
contents: read

jobs:
analyze:
name: Analyze (javascript-typescript)
runs-on: ubuntu-latest
permissions:
contents: read
# Required to upload results to code scanning.
security-events: write
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0

- uses: github/codeql-action/init@a2983b8bed1923f44751c5c43237f479442827b3 # v3.37.4
with:
languages: javascript-typescript
build-mode: none

- uses: github/codeql-action/analyze@a2983b8bed1923f44751c5c43237f479442827b3 # v3.37.4
with:
category: "/language:javascript-typescript"
45 changes: 45 additions & 0 deletions .github/workflows/gitleaks.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Secret scan: gitleaks over the full git history.
#
# Deliberately NOT gitleaks/gitleaks-action — that action requires a paid
# GITLEAKS_LICENSE for organization-owned repos. The scanner itself is a
# single MIT-licensed Go binary, so this downloads a pinned release and
# verifies its sha256 (from the upstream release checksums file) before
# running it. fetch-depth: 0 so every commit is scanned, not just the PR
# head — a secret that was committed and later deleted is still leaked.
# Known fake secrets (test fixtures, docs placeholders) are allowlisted
# in .gitleaks.toml at the repo root; anything new fails the run.
name: Secret scan

on:
push:
branches: [main]
pull_request:
branches: [main]

permissions:
contents: read

jobs:
gitleaks:
name: gitleaks (full history)
runs-on: ubuntu-latest
env:
GITLEAKS_VERSION: 8.30.1
# sha256 of gitleaks_8.30.1_linux_x64.tar.gz, from
# gitleaks_8.30.1_checksums.txt on the upstream release.
GITLEAKS_SHA256: 551f6fc83ea457d62a0d98237cbad105af8d557003051f41f3e7ca7b3f2470eb
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
with:
# Full history — gitleaks scans commits, not the working tree.
fetch-depth: 0

- name: Download and verify gitleaks
run: |
curl -sSfL -o gitleaks.tar.gz \
"https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz"
echo "${GITLEAKS_SHA256} gitleaks.tar.gz" | sha256sum -c -
tar -xzf gitleaks.tar.gz gitleaks

- name: Scan full history
run: ./gitleaks detect --no-banner --redact
43 changes: 43 additions & 0 deletions .github/workflows/scorecard.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# OpenSSF Scorecard: automated checks of this repo's own security posture
# (branch protection, token permissions, pinned dependencies, ...).
#
# Runs on pushes to main plus a weekly cron — Scorecard rates the repo, not
# a PR's diff, so there is no pull_request trigger. publish_results: true
# sends the score to the OpenSSF public API (which enables the README badge
# and is what other tools query); that upload is signed via OIDC, hence
# id-token: write. Results also land in the Security tab as SARIF.
name: Scorecard

on:
push:
branches: [main]
schedule:
# Mondays 05:30 UTC.
- cron: "30 5 * * 1"

permissions: read-all

jobs:
analysis:
name: Scorecard analysis
runs-on: ubuntu-latest
permissions:
# Needed to sign the published results (OIDC).
id-token: write
# Needed to upload SARIF to code scanning.
security-events: write
contents: read
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0
with:
persist-credentials: false

- uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3
with:
results_file: results.sarif
results_format: sarif
publish_results: true

- uses: github/codeql-action/upload-sarif@a2983b8bed1923f44751c5c43237f479442827b3 # v3.37.4
with:
sarif_file: results.sarif
37 changes: 37 additions & 0 deletions .gitleaks.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# gitleaks config for the Secret scan workflow (.github/workflows/gitleaks.yml).
#
# Default rules apply everywhere. The allowlist below suppresses EXACT known
# fake secret values (anchored regexes tested against the found secret), not
# files: every entry is one verified fixture string. A real credential added
# anywhere — including to the files that hold these fixtures — would still
# fail the scan, because its value cannot equal a known fake.
#
# Deliberately NOT path-based. Verified against gitleaks 8.30.1 by planting
# a high-entropy secret in an allowlisted fixture file and scanning history:
# a path-only allowlist swallows it (0 leaks reported), this config flags it.
# Path entries also make `gitleaks dir` skip the whole file unread, so even
# a path+value AND combination is a trap for anyone scanning the worktree.
#
# The scan covers full git history, so entries must keep matching fixtures
# in old commits even if the files that hold them later move or change.

[extend]
useDefault = true

[[allowlists]]
description = "safeError unit-test fixtures: fake OpenAI-style key and fake token used to prove secrets get scrubbed from error output (backend/src/lib/__tests__/safeError.test.ts)"
regexes = [
'''^sk-proj-abc123def456ghi789\.?$''',
'''^abcdef123456$''',
]

[[allowlists]]
description = "Word add-in e2e fixture: mocked session token for the hermetic auth spec (word-addin/e2e/auth.spec.ts)"
regexes = ['''^valid-jwt-123$''']

[[allowlists]]
description = "Supabase's public demo JWTs (iss: supabase-demo, HS256-signed with the published demo secret — the well-known local-dev anon/service_role keys from Supabase's own docs) in .env.example / docker-compose.yml history"
regexes = [
'''^eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9\.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9\.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0$''',
'''^eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9\.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImV4cCI6MTk4MzgxMjk5Nn0\.EGIM96RAZx35lJzdJsyH-qQwv8Hdp7fsn3W0YpN81IU$''',
]
45 changes: 45 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# Security Policy

## Supported versions

| Version | Supported |
| --- | --- |
| tip of `main` | ✅ |
| tagged releases (`v0.1.0`–`v0.4.0`) | ❌ |

Security fixes land only on `main`; the existing tags are historical
snapshots and do not receive backported fixes. If you are self-hosting,
please update to the latest `main` before reporting — the issue may already
be fixed.

## Reporting a vulnerability

Please report vulnerabilities privately through GitHub:

**Security tab → Report a vulnerability** on this repository
(GitHub's private vulnerability reporting).

Please do not open a public issue for anything security-sensitive.

This project has a solo maintainer. You can expect an acknowledgment within
7 days; fixes are prioritized by severity after that.

## Scope

- Reports about the code, default configuration, and deployment guidance in
this repo are all in scope.
- The **hosted service at `app.mikeoss.com`** (the cloud version offered from
the official Mike website) is in scope — report issues affecting it through
the same private channel above, and please keep testing non-destructive:
only accounts and data you own, no denial of service, no access to other
users' data beyond the minimum proof needed.
- **Independent self-hosted installations** run by third parties are the one
exclusion: findings that only apply to how a specific outside operator has
deployed Mike (their infrastructure, their configuration) should go to
whoever operates that deployment.
- Mike is an **LLM legal product**, so LLM-specific reports are explicitly
welcome: prompt injection (including via uploaded documents), getting the
model to ignore its guardrails, leaking another user's data or system
prompts through model output, and similar.
- Secrets accidentally committed to this repository's history are also worth
a private report, even though CI runs a secret scanner.
Loading