You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Major fixes
- package.json: wire `tsc --noEmit` into `build` via new `typecheck`
script. tsup transpiles but does not enforce TS diagnostics; the
safety net is back.
- tsconfig.json: move to `module: NodeNext` / `moduleResolution: nodenext`
and `target: ES2022` so the deprecated `node10` path no longer
blocks tsc, `resolveJsonModule` added for completeness.
- src/*.ts: real unknown-error narrowing in 3 catch blocks, null-safe
payload access in download_attachment, GmailLabel/GmailMessagePart
now typed via `gmail_v1.Schema$*` instead of hand-written shapes
that were stricter than the SDK reality.
- CHANGELOG.md: promote the accumulated content to `[0.1.0] - 2026-04-22`
so the release-notes extractor can match the first tag. A fresh
`[Unreleased]` stub keeps the next cycle unblocked.
- codecov.yml: drop `if_no_uploads: success` / `if_not_found: success`.
Missing coverage now fails the gate instead of silently no-op'ing.
Add an `ignore` list for doc/config-only PRs that legitimately
produce no coverage.
- ASSURANCE_CASE.md CWE-79: reclassify from "N/A — no HTML output" to
"out-of-scope for this process", documenting that download_email /
read_email do surface HTML bodies and the consumer is responsible
for sanitisation before rendering.
Minor
- ASSURANCE_CASE.md: Scorecard trigger description now matches the
actual workflow (push to main + weekly + branch_protection_rule,
not every commit).
- README.md: `gmail.readonly` scope row now clarifies that filter
tools require `gmail.settings.basic`.
Trivial
- ci.yml: coverage instrumentation runs only on the Node 20 axis; the
22/24 axes run plain `npm test` so we do not pay the vitest-v8
overhead three times for one coverage upload. `fail_ci_if_error` on
Codecov is now `true`.
- reply-all-helpers.test.ts: two regression tests lock the quoted-
comma parser ('Doe, John' and multi-entry variants).
Tests: 129/129. Build + lint + format:check clean.
Copy file name to clipboardExpand all lines: ASSURANCE_CASE.md
+2-2Lines changed: 2 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -145,7 +145,7 @@ and scope filtering all live at that boundary.
145
145
|**Fail closed**| Missing `~/.gmail-mcp/gcp-oauth.keys.json` → exit at startup with a clear error. Attachment path outside the jail → refuse before any write. Non-loopback OAuth callback hostname → reject at `authenticate()`. Invalid Zod input → refuse before the Gmail API call. |
146
146
|**Minimise attack surface**| Single-file ESM bundle via `tsup` (no sourcemaps in the published tarball); only `dist/`, `README.md`, `LICENSE` in the npm files allowlist. No HTTP transport (stdio only) outside of the one-shot OAuth callback server. Tool list gated by OAuth scope. |
147
147
|**Secrets are env-only / local-only**| OAuth refresh token at `~/.gmail-mcp/credentials.json` (mode `0o600`); client keys at `~/.gmail-mcp/gcp-oauth.keys.json` (user-provided). No secret ever travels over MCP stdout or MCP tool results. |
148
-
|**Auditable & reproducible**| Every release is Sigstore-signed and SLSA-attested. Every commit triggers CI on Node 20/22/24 + CodeQL + Scorecard + Socket + CodeRabbit. |
148
+
|**Auditable & reproducible**| Every release is Sigstore-signed and SLSA-attested. Every commit triggers CI on Node 20/22/24 + CodeQL + Socket + CodeRabbit. OpenSSF Scorecard runs on push to `main`, weekly on Monday, and on branch-protection rule changes (not on every PR commit). |
149
149
|**Open source, MIT**| Anyone can audit. Project continuity documented in [CONTINUITY.md](./CONTINUITY.md). |
150
150
151
151
## 4. Common implementation weaknesses countered
@@ -158,7 +158,7 @@ Mapped to [CWE](https://cwe.mitre.org/) and [OWASP Top 10](https://owasp.org/Top
158
158
|**CWE-59** Symlink following | Countered | Every leaf file write uses `fs.openSync` with `O_NOFOLLOW`; a pre-existing symlink at the destination causes the open to fail. |
159
159
|**CWE-78 / CWE-94** Command / code injection | N/A | No `child_process`, no `eval`, no dynamic `require`. |
160
160
|**CWE-89** SQL injection | N/A | No database. |
161
-
|**CWE-79** XSS |N/A | No HTML output. |
161
+
|**CWE-79** XSS |Out-of-scope for this process (MCP never renders HTML) — downstream responsibility | The `download_email` tool writes HTML bodies (via `emailToHtml()`) verbatim to `GMAIL_MCP_DOWNLOAD_DIR` and the `read_email` tool returns HTML string content to the MCP client. This MCP does not render HTML itself. If the consuming agent forwards that HTML to a browser, PDF pipeline, or any other HTML-executing surface, the agent must sanitise before rendering. Flagged transparently rather than claimed N/A. |
162
162
|**CWE-88 / CWE-93 / CWE-113** CRLF / header injection | Countered |`sanitizeHeaderValue` strips `\r`, `\n`, `\0` from every user-supplied RFC-822 header value (`From`, `To`, `Cc`, `Bcc`, `Subject`, `In-Reply-To`, `References`). |
163
163
|**CWE-117** Log injection | N/A | MCP emits no log file of its own (tracked as a future audit-log feature in [SECURITY.md](./SECURITY.md)). |
164
164
|**CWE-200 / CWE-209** Information exposure / verbose errors | Countered | Error messages never include the OAuth refresh token or the Google OAuth client secret. |
Copy file name to clipboardExpand all lines: CHANGELOG.md
+6Lines changed: 6 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -9,6 +9,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
9
9
10
10
### Added
11
11
12
+
- Placeholder for the next release cycle.
13
+
14
+
## [0.1.0] - 2026-04-22
15
+
16
+
### Added
17
+
12
18
-**Attachment jail** (`GMAIL_MCP_ATTACHMENT_DIR`, default `~/GmailAttachments/`, mode `0o700`). Every attachment path passed to `send_email` / `draft_email` / `reply_all` is `realpath`-canonicalized and rejected if it escapes the jail. Symlink-to-outside is rejected. Closes the headline prompt-injection exfiltration vector (a crafted inbound email instructing the agent to attach `~/.ssh/id_rsa` etc.).
13
19
-**Download jail** (`GMAIL_MCP_DOWNLOAD_DIR`, default `~/GmailDownloads/`, mode `0o700`). `download_email` and `download_attachment` write exclusively inside this directory. The leaf is opened with `O_NOFOLLOW` so a pre-existing symlink at the destination cannot be used to escape. Post-`mkdir` the resolved path is re-verified against the jail root (TOCTOU defense).
0 commit comments