zer0-agent 0.1.0 → 0.1.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/dist/api.js +6 -0
- package/dist/config.js +1 -1
- package/dist/context/todos.js +18 -3
- package/package.json +1 -1
package/dist/api.js
CHANGED
|
@@ -5,6 +5,12 @@ function makeRequest(url, method, token, body) {
|
|
|
5
5
|
return new Promise((resolve, reject) => {
|
|
6
6
|
const parsed = new URL(url);
|
|
7
7
|
const isHttps = parsed.protocol === "https:";
|
|
8
|
+
const isLocalhost = parsed.hostname === "localhost" || parsed.hostname === "127.0.0.1";
|
|
9
|
+
// SECURITY: Enforce HTTPS for non-localhost servers
|
|
10
|
+
if (!isHttps && !isLocalhost) {
|
|
11
|
+
reject(new Error(`Refusing to send agent token over insecure HTTP to ${parsed.hostname}. Use HTTPS.`));
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
8
14
|
const reqFn = isHttps ? httpsRequest : httpRequest;
|
|
9
15
|
const options = {
|
|
10
16
|
hostname: parsed.hostname,
|
package/dist/config.js
CHANGED
|
@@ -22,7 +22,7 @@ export function loadConfig() {
|
|
|
22
22
|
}
|
|
23
23
|
export function saveConfig(config) {
|
|
24
24
|
if (!existsSync(CONFIG_DIR)) {
|
|
25
|
-
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
25
|
+
mkdirSync(CONFIG_DIR, { recursive: true, mode: 0o700 });
|
|
26
26
|
}
|
|
27
27
|
writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2) + "\n");
|
|
28
28
|
// Secure the config — token should not be world-readable
|
package/dist/context/todos.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { existsSync, readFileSync } from "fs";
|
|
2
|
-
import { join } from "path";
|
|
1
|
+
import { existsSync, readFileSync, lstatSync, realpathSync } from "fs";
|
|
2
|
+
import { join, resolve } from "path";
|
|
3
3
|
const TODO_FILES = [
|
|
4
4
|
"TODO.md",
|
|
5
5
|
"TODO",
|
|
@@ -9,13 +9,28 @@ const TODO_FILES = [
|
|
|
9
9
|
"TASKS.md",
|
|
10
10
|
".todo",
|
|
11
11
|
];
|
|
12
|
+
const MAX_FILE_SIZE = 50_000; // 50KB — don't read huge files
|
|
12
13
|
export function gatherTodos(cwd) {
|
|
13
14
|
const todos = [];
|
|
15
|
+
const resolvedCwd = resolve(cwd);
|
|
14
16
|
for (const file of TODO_FILES) {
|
|
15
|
-
const filepath = join(
|
|
17
|
+
const filepath = join(resolvedCwd, file);
|
|
16
18
|
if (!existsSync(filepath))
|
|
17
19
|
continue;
|
|
18
20
|
try {
|
|
21
|
+
// SECURITY: Prevent symlink attacks — only read regular files
|
|
22
|
+
// that resolve within the project directory
|
|
23
|
+
const stat = lstatSync(filepath);
|
|
24
|
+
if (stat.isSymbolicLink())
|
|
25
|
+
continue;
|
|
26
|
+
if (!stat.isFile())
|
|
27
|
+
continue;
|
|
28
|
+
if (stat.size > MAX_FILE_SIZE)
|
|
29
|
+
continue;
|
|
30
|
+
// Double-check the real path stays within the project
|
|
31
|
+
const realPath = realpathSync(filepath);
|
|
32
|
+
if (!realPath.startsWith(resolvedCwd))
|
|
33
|
+
continue;
|
|
19
34
|
const content = readFileSync(filepath, "utf-8");
|
|
20
35
|
const lines = content.split("\n");
|
|
21
36
|
for (const line of lines) {
|