canship 0.1.1 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README-zh-CN.md +125 -0
- package/README.md +81 -70
- package/dist/cli.js +1289 -319
- package/package.json +2 -2
- package/README.zh-CN.md +0 -116
package/README-zh-CN.md
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# canship
|
|
2
|
+
|
|
3
|
+
面向 JavaScript / TypeScript 项目的本地静态扫描器,检测凭据暴露和访问控制配置错误。不执行项目代码,不上传文件,扫描过程不联网。
|
|
4
|
+
|
|
5
|
+
```powershell
|
|
6
|
+
npx canship .
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
要求 Node.js ≥18,无运行时依赖。Git 用于读取本地历史;仓库中无法使用 Git 时,扫描标记为未完成。首次使用 `npx` 可能需要从 npm 下载软件包。
|
|
10
|
+
|
|
11
|
+
[English](./README.md)
|
|
12
|
+
|
|
13
|
+
## 检测范围
|
|
14
|
+
|
|
15
|
+
| 检查项 | 级别 |
|
|
16
|
+
|---|---|
|
|
17
|
+
| 硬编码凭据、私钥及含密码的数据库连接串 | P0 |
|
|
18
|
+
| 公开环境变量中的私密值 | P0 |
|
|
19
|
+
| 客户端可访问的 Supabase 管理员密钥 | P0 |
|
|
20
|
+
| Git 跟踪及历史 `.env` 文件中的凭据或疑似私密值 | P0 |
|
|
21
|
+
| Supabase 表未启用行级安全(RLS) | P1 |
|
|
22
|
+
| Firebase 无条件访问及固定日期测试规则 | P1 |
|
|
23
|
+
| Next.js API 数据操作缺少鉴权 | P0 / P1 |
|
|
24
|
+
| 携带凭据的 CORS 来源回显或通配符配置 | P1 / P2 |
|
|
25
|
+
|
|
26
|
+
识别 OpenAI、Anthropic、AWS、Stripe、GitHub、npm、Slack、SendGrid 等凭据格式及常见前端框架的公开环境变量前缀。API 鉴权检查限于 Next.js 的 `/api` 处理函数,支持 App Router、Pages Router、路由组和工作区应用。
|
|
27
|
+
|
|
28
|
+
置信度分为确定(`certain`)和疑似(`likely`)。默认只展示确定结果;隐藏的疑似结果仍影响退出码。
|
|
29
|
+
|
|
30
|
+
## 参数
|
|
31
|
+
|
|
32
|
+
省略路径时扫描当前目录。
|
|
33
|
+
|
|
34
|
+
| 参数 | 说明 |
|
|
35
|
+
|---|---|
|
|
36
|
+
| `-a`, `--all` | 展示疑似结果 |
|
|
37
|
+
| `--json` | 输出 JSON |
|
|
38
|
+
| `--fix-prompt` | 输出编程助手修复指令及独立的人工操作清单 |
|
|
39
|
+
| `--report[=文件]` | 写入 HTML 报告,默认 `canship-report.html` |
|
|
40
|
+
| `--sarif[=文件]` | 写入 SARIF 2.1.0 报告,默认 `canship.sarif` |
|
|
41
|
+
| `--best-effort` | 无结果时,允许不完整扫描退出 `0` |
|
|
42
|
+
| `--baseline[=文件]` | 应用基线,默认 `canship-baseline.json` |
|
|
43
|
+
| `--baseline-write[=文件]` | 记录当前结果为基线后退出 |
|
|
44
|
+
| `--only=规则` | 仅执行匹配规则,支持逗号分隔及重复参数 |
|
|
45
|
+
| `--skip=规则` | 排除匹配规则,支持逗号分隔及重复参数 |
|
|
46
|
+
| `--no-config` | 忽略项目配置 |
|
|
47
|
+
| `-h`, `--help` | 显示帮助 |
|
|
48
|
+
| `-v`, `--version` | 显示版本 |
|
|
49
|
+
|
|
50
|
+
`--json` 与 `--fix-prompt` 互斥;HTML 和 SARIF 可与任一输出模式组合。报告正文为英文,各格式均用 `--all` 包含疑似结果。
|
|
51
|
+
|
|
52
|
+
### 退出码
|
|
53
|
+
|
|
54
|
+
| 退出码 | 含义 |
|
|
55
|
+
|---|---|
|
|
56
|
+
| `0` | 无结果且扫描完整,或由 `--best-effort` 接受不完整扫描 |
|
|
57
|
+
| `1` | 存在 `certain` 的 P0/P1 结果 |
|
|
58
|
+
| `2` | 存在其他结果,包括被隐藏的 `likely` |
|
|
59
|
+
| `3` | 参数或工具错误,或未被接受的不完整扫描 |
|
|
60
|
+
|
|
61
|
+
结果对应的退出码优先于不完整状态;`--best-effort` 不改变 `1` 或 `2`。JSON 用 `partial`、`errors`、`skipped` 保留完整性信息,SARIF 提供执行状态和诊断通知。
|
|
62
|
+
|
|
63
|
+
## 配置与忽略
|
|
64
|
+
|
|
65
|
+
扫描目录中的 `canship.config.json` 支持 `baseline`、`only`、`skip`、`all`:
|
|
66
|
+
|
|
67
|
+
```json
|
|
68
|
+
{
|
|
69
|
+
"skip": ["cors/wildcard-with-credentials"],
|
|
70
|
+
"all": false
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
命令行参数优先;`only` 与 `skip` 互斥,接受完整规则 ID 或命名空间。无关规则不执行;`ruleSelection.removed` 仅统计已执行规则中被过滤的结果。扫描不可信项目时使用 `--no-config`;`bestEffort` 仅支持命令行设置。
|
|
75
|
+
|
|
76
|
+
以独占注释行的 `canship-ignore-file` 排除整个文件,或用 `canship-ignore-next-line` 忽略下一行。后者可附加规则 ID:
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
// canship-ignore-next-line cors/wildcard-with-credentials
|
|
80
|
+
const corsOptions = { origin: '*', credentials: true }
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
报告披露忽略、筛选和基线抑制信息。主动忽略不使扫描标记为未完成。
|
|
84
|
+
|
|
85
|
+
## 基线
|
|
86
|
+
|
|
87
|
+
记录已有结果:
|
|
88
|
+
|
|
89
|
+
```powershell
|
|
90
|
+
npx canship --baseline-write
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
仅报告新增结果:
|
|
94
|
+
|
|
95
|
+
```powershell
|
|
96
|
+
npx canship --baseline
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
裸参数使用扫描目录,显式路径相对工作目录。写入成功退出 `0`;扫描不完整或启用规则筛选时会提示。
|
|
100
|
+
|
|
101
|
+
基线格式为第 2 版,不含源码摘录,但披露路径、规则、标题和问题类型,提交前需审阅。指纹不含行号,移动行号不会产生新结果,替换凭据会。缺失、损坏及第 1 版基线均退出 `3`。
|
|
102
|
+
|
|
103
|
+
## 限制
|
|
104
|
+
|
|
105
|
+
- 静态启发式分析可能误报或漏报,不验证运行时行为、限流、注入、依赖漏洞及业务授权。无发现不代表项目安全。
|
|
106
|
+
- 脱敏仅覆盖已识别格式;未知秘密可能出现在证据行中,报告应作为内部材料。Google/Firebase/Maps 的 `AIza...` 值按公开标识符处理。
|
|
107
|
+
- 单文件最多读取 2 MiB;单次累计读取最多 128 MiB、10,000 个文件;目录最多 16 层。跨规则每文件最多输出 100 条结果,优先保留高严重度、高置信度结果。
|
|
108
|
+
- Git 历史每文件最多检查 100 个相关版本,单条 Git 命令超时为 30 秒。超限或超时均披露检查缺口。
|
|
109
|
+
- 不跟随符号链接;嵌套仓库及子模块需分别扫描。扫描范围内的跳过项使扫描未完成,已排除的构建和依赖目录除外。
|
|
110
|
+
|
|
111
|
+
## 开发
|
|
112
|
+
|
|
113
|
+
检测规则需同时包含应检出和不应检出的用例,参见 [测试夹具](./test/fixtures/)。
|
|
114
|
+
|
|
115
|
+
```powershell
|
|
116
|
+
npm ci
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
```powershell
|
|
120
|
+
npm run prepublishOnly
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## 许可
|
|
124
|
+
|
|
125
|
+
[MIT](./LICENSE)
|
package/README.md
CHANGED
|
@@ -1,111 +1,122 @@
|
|
|
1
1
|
# canship
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A local static scanner for JavaScript and TypeScript projects. Detects exposed credentials and access-control misconfigurations without executing project code, uploading files, or making network requests during scans.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
npx canship
|
|
5
|
+
```powershell
|
|
6
|
+
npx canship .
|
|
9
7
|
```
|
|
10
8
|
|
|
11
|
-
Node.js 18
|
|
9
|
+
Requires Node.js ≥18; no runtime dependencies. Git is used for local history checks. Unavailable Git in a repository makes the scan incomplete. On first use, `npx` may download the package from npm.
|
|
12
10
|
|
|
13
|
-
[简体中文](./README
|
|
11
|
+
[简体中文](./README-zh-CN.md)
|
|
14
12
|
|
|
15
13
|
## Checks
|
|
16
14
|
|
|
17
|
-
| Check |
|
|
18
|
-
|
|
19
|
-
| Hardcoded credentials
|
|
20
|
-
| Private values in public environment variables |
|
|
21
|
-
| Supabase
|
|
22
|
-
|
|
|
23
|
-
| Supabase tables without
|
|
24
|
-
| Firebase
|
|
25
|
-
| Next.js API
|
|
26
|
-
| CORS
|
|
27
|
-
|
|
28
|
-
Severity (P0, P1, P2) describes potential impact. Confidence (`certain`, `likely`) describes how strongly the code supports the finding. A `certain` P0/P1 finding blocks release and exits with status `1`; all other findings exit with status `2`.
|
|
29
|
-
|
|
30
|
-
`Access-Control-Allow-Origin: *` combined with credentials is reported at P2 because browsers reject that configuration. A bare wildcard is not reported.
|
|
15
|
+
| Check | Severity |
|
|
16
|
+
|---|---|
|
|
17
|
+
| Hardcoded credentials, private keys, and database URLs containing passwords | P0 |
|
|
18
|
+
| Private values in public environment variables | P0 |
|
|
19
|
+
| Client-accessible Supabase admin keys | P0 |
|
|
20
|
+
| Credentials or suspected private values in Git-tracked and historical `.env` files | P0 |
|
|
21
|
+
| Supabase tables without Row Level Security (RLS) | P1 |
|
|
22
|
+
| Firebase unconditional access and date-based test rules | P1 |
|
|
23
|
+
| Next.js API data operations without authentication | P0 / P1 |
|
|
24
|
+
| Credentialed CORS with reflected or wildcard origins | P1 / P2 |
|
|
31
25
|
|
|
32
|
-
|
|
26
|
+
Recognises OpenAI, Anthropic, AWS, Stripe, GitHub, npm, Slack, SendGrid, and other credential formats, plus common frontend public environment prefixes. API authentication checks cover Next.js `/api` handlers, including App Router, Pages Router, route groups, and workspace applications.
|
|
33
27
|
|
|
34
|
-
|
|
28
|
+
Confidence is `certain` or `likely`. Only certain findings are shown by default; hidden likely findings still affect the exit code.
|
|
35
29
|
|
|
36
|
-
|
|
37
|
-
npx canship [path]
|
|
38
|
-
```
|
|
30
|
+
## Options
|
|
39
31
|
|
|
40
|
-
|
|
32
|
+
Omitting the path scans the current directory.
|
|
41
33
|
|
|
42
34
|
| Option | Description |
|
|
43
35
|
|---|---|
|
|
44
|
-
| `-a`, `--all` |
|
|
45
|
-
| `--json` |
|
|
46
|
-
| `--fix-prompt` |
|
|
47
|
-
| `--report[=file]` | Write
|
|
48
|
-
| `--
|
|
36
|
+
| `-a`, `--all` | Include likely findings |
|
|
37
|
+
| `--json` | Output JSON |
|
|
38
|
+
| `--fix-prompt` | Output assistant instructions and separate manual actions |
|
|
39
|
+
| `--report[=file]` | Write HTML; default: `canship-report.html` |
|
|
40
|
+
| `--sarif[=file]` | Write SARIF 2.1.0; default: `canship.sarif` |
|
|
41
|
+
| `--best-effort` | Permit exit `0` for an incomplete scan with no findings |
|
|
42
|
+
| `--baseline[=file]` | Apply a baseline; default: `canship-baseline.json` |
|
|
43
|
+
| `--baseline-write[=file]` | Record current findings as a baseline and exit |
|
|
44
|
+
| `--only=ids` | Run matching rules; comma-separated and repeatable |
|
|
45
|
+
| `--skip=ids` | Exclude matching rules; comma-separated and repeatable |
|
|
46
|
+
| `--no-config` | Ignore project configuration |
|
|
49
47
|
| `-h`, `--help` | Show help |
|
|
50
|
-
| `-v`, `--version` | Show
|
|
48
|
+
| `-v`, `--version` | Show version |
|
|
51
49
|
|
|
52
|
-
`--json` and `--fix-prompt` are mutually exclusive.
|
|
50
|
+
`--json` and `--fix-prompt` are mutually exclusive. HTML and SARIF may be combined with either. Reports are in English; use `--all` to include likely findings in any format.
|
|
53
51
|
|
|
54
|
-
### Exit
|
|
52
|
+
### Exit codes
|
|
55
53
|
|
|
56
|
-
|
|
|
54
|
+
| Code | Meaning |
|
|
57
55
|
|---|---|
|
|
58
|
-
| `0` | No findings
|
|
59
|
-
| `1` | At least one
|
|
60
|
-
| `2` |
|
|
61
|
-
| `3` | Invalid arguments, a tool error, or an incomplete scan
|
|
56
|
+
| `0` | No findings and a complete scan, or an incomplete scan accepted with `--best-effort` |
|
|
57
|
+
| `1` | At least one certain P0/P1 finding |
|
|
58
|
+
| `2` | Other findings, including hidden likely findings |
|
|
59
|
+
| `3` | Invalid arguments, a tool error, or an unaccepted incomplete scan |
|
|
62
60
|
|
|
63
|
-
|
|
61
|
+
Findings take precedence over incompleteness; `--best-effort` does not change `1` or `2`. JSON retains `partial`, `errors`, and `skipped`; SARIF includes execution status and diagnostic notifications.
|
|
64
62
|
|
|
65
|
-
|
|
63
|
+
## Configuration and suppressions
|
|
66
64
|
|
|
67
|
-
|
|
65
|
+
Place `canship.config.json` in the scanned directory. Supported keys: `baseline`, `only`, `skip`, `all`.
|
|
68
66
|
|
|
69
|
-
|
|
67
|
+
```json
|
|
68
|
+
{
|
|
69
|
+
"skip": ["cors/wildcard-with-credentials"],
|
|
70
|
+
"all": false
|
|
71
|
+
}
|
|
72
|
+
```
|
|
70
73
|
|
|
71
|
-
|
|
74
|
+
CLI options take precedence. `only` and `skip` are mutually exclusive and accept complete rule IDs or namespaces. Unrelated rules do not run; `ruleSelection.removed` counts only filtered findings from rules that ran. Use `--no-config` for untrusted projects. `bestEffort` is CLI-only.
|
|
72
75
|
|
|
73
|
-
|
|
76
|
+
A standalone comment containing `canship-ignore-file` excludes a file. `canship-ignore-next-line` suppresses the next line and accepts an optional rule ID:
|
|
74
77
|
|
|
75
|
-
|
|
78
|
+
```ts
|
|
79
|
+
// canship-ignore-next-line cors/wildcard-with-credentials
|
|
80
|
+
const corsOptions = { origin: '*', credentials: true }
|
|
81
|
+
```
|
|
76
82
|
|
|
77
|
-
|
|
78
|
-
|---|---|
|
|
79
|
-
| Public environment variables | The name starts with `NEXT_PUBLIC_`, `VITE_`, `REACT_APP_`, `EXPO_PUBLIC_`, `NUXT_PUBLIC_`, `GATSBY_`, `VUE_APP_`, or `PUBLIC_` |
|
|
80
|
-
| Git-tracked environment files | The target is inside a readable local Git repository whose `.git` metadata is inside the checkout or names it back; templates, public values, placeholders, and short settings are excluded, and at most the 100 most recent relevant revisions of each file are inspected |
|
|
81
|
-
| Next.js API authentication | Only data-accessing handlers under `app/api/**` and `pages/api/**`; recognises enforcing authentication calls, identity conditions that control rejection, and middleware `matcher` coverage for the route |
|
|
82
|
-
| Supabase RLS | The current project scope contains `supabase/`, an `@supabase/supabase-js` or `@supabase/ssr` import, or a `SUPABASE_URL`; table-related DDL is replayed across migrations within that project scope |
|
|
83
|
-
| Other credential and configuration rules | Match known file formats and content patterns without requiring a specific front-end framework |
|
|
83
|
+
Reports disclose exclusions, rule selection, and baseline suppression. Deliberate exclusions do not make the scan incomplete.
|
|
84
84
|
|
|
85
|
-
##
|
|
85
|
+
## Baselines
|
|
86
86
|
|
|
87
|
-
|
|
88
|
-
- Detection and redaction use the same credential patterns. A credential that canship cannot recognise cannot be guaranteed to be masked; if another rule quotes the same line, the original value may appear in the report. Treat reports as internal material.
|
|
89
|
-
- Entropy-based detection is intentionally not used because random identifiers, hashes, and ordinary Base64 text cannot be classified reliably from entropy alone.
|
|
90
|
-
- Files are limited to 2 MiB, traversal to 16 directory levels, and output to 100 findings per file. Git history checks inspect at most the 100 most recent relevant revisions of each file. Reaching a limit is recorded explicitly.
|
|
91
|
-
- Symbolic links are not followed and make the scan incomplete.
|
|
92
|
-
- Nested Git repositories and submodules are not expanded by the parent scan. They are listed as skipped and the parent scan is marked incomplete.
|
|
93
|
-
- A `.git` file may point outside the checkout. canship follows it only when the target names this checkout back, which is what git records for a linked worktree and for a submodule. Anything else is read as a redirect to an unrelated repository: file scanning continues, history checks are marked incomplete.
|
|
94
|
-
- Google, Firebase, and Maps `AIza...` keys are treated as public identifiers. Their application and API restrictions exist in Google Cloud and cannot be verified from local source, so the key value alone is not reported as a credential leak.
|
|
95
|
-
- Rate limiting, injection, dependency vulnerabilities, and business authorisation beyond caller authentication are outside the scan scope.
|
|
87
|
+
Record existing findings:
|
|
96
88
|
|
|
97
|
-
|
|
89
|
+
```powershell
|
|
90
|
+
npx canship --baseline-write
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Report only new findings:
|
|
94
|
+
|
|
95
|
+
```powershell
|
|
96
|
+
npx canship --baseline
|
|
97
|
+
```
|
|
98
98
|
|
|
99
|
-
|
|
99
|
+
Bare options use the scanned directory; explicit paths are relative to the working directory. A successful write exits `0`, with a warning for incomplete or selectively scanned input.
|
|
100
100
|
|
|
101
|
-
|
|
101
|
+
Baseline format v2 contains no source excerpts but discloses paths, rules, titles, and issue types. Review it before committing. Fingerprints exclude line numbers: moving lines preserves identity, replacing credentials changes it. Missing, malformed, and v1 baselines exit `3`.
|
|
102
102
|
|
|
103
|
-
##
|
|
103
|
+
## Limitations
|
|
104
104
|
|
|
105
|
-
|
|
105
|
+
- Static heuristics may produce false positives or negatives. Runtime behaviour, rate limiting, injection, dependency vulnerabilities, and business authorisation are outside scope. No findings does not prove security.
|
|
106
|
+
- Redaction covers recognised formats only; unknown secrets may appear in evidence. Treat reports as internal material. Google/Firebase/Maps `AIza...` values are treated as public identifiers.
|
|
107
|
+
- Reads are limited to 2 MiB per file, 128 MiB and 10,000 files per scan, and 16 directory levels. Across rules, at most 100 findings per file are reported, prioritising severity and confidence.
|
|
108
|
+
- Git history checks cover up to 100 relevant revisions per file. Each Git command has a 30-second timeout. Exceeded limits and timeouts are reported as incomplete coverage.
|
|
109
|
+
- Symbolic links are not followed. Scan nested repositories and submodules separately. Skipped paths within scope make the scan incomplete; excluded build and dependency directories remain excluded.
|
|
106
110
|
|
|
107
|
-
|
|
111
|
+
## Development
|
|
112
|
+
|
|
113
|
+
Detection rules require positive and negative cases; see [test fixtures](./test/fixtures/).
|
|
114
|
+
|
|
115
|
+
```powershell
|
|
108
116
|
npm ci
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
```powershell
|
|
109
120
|
npm run prepublishOnly
|
|
110
121
|
```
|
|
111
122
|
|