Skip to content

Implement audit roadmap: security hardening, reliability, and CI.#3

Merged
MParvin merged 4 commits into
masterfrom
cursor/audit-roadmap-implementation
Jul 15, 2026
Merged

Implement audit roadmap: security hardening, reliability, and CI.#3
MParvin merged 4 commits into
masterfrom
cursor/audit-roadmap-implementation

Conversation

@MParvin

@MParvin MParvin commented Jul 15, 2026

Copy link
Copy Markdown
Owner

Close permission bypasses for all tools, fix Docker argv isolation and goal resume, add tests and DevOps docs, and stop tracking personal config.yaml.


Note

High Risk
Broad changes to permission enforcement, SSRF/SSH/browser auth, and the goal state machine affect every tool invocation and resume path; mistakes could block legitimate work or leave bypasses.

Overview
This PR implements an audit roadmap: tightens tool permissions and isolation, improves goal execution reliability, and adds CI, container, and contributor docs.

Security & permissions: permission.Manager now gates every built-in tool (unknown tools deny by default), resolves paths via projects_root, normalizes deny-list matching, checks command cwd, HTTP/git URLs with SSRF rules and optional allow_http_hosts, browser domains and JS execution approvals, and git push approval. SSH uses known_hosts instead of insecure host-key skip and quotes remote paths. Browser WebSocket requires a token, rejects missing auth, and restricts Origin to extensions/localhost. Personal config.yaml is removed from the repo and ignored.

Execution & reliability: The engine resumes goals in EXECUTING/EVALUATING/RETRYING, skips terminal states, resets stuck running tasks, and persists checkpoints during loops. Step evaluation uses ViewWithOutput so evaluators see fresh tool results. Docker isolation passes _docker_argv and runs via exec without flattening the command string; permissions run before wrapping.

Product & DX: New octa-agent CLI (goals with --project, status, logs, approvals) and octa-agentd (5s polling, concurrent goals, graceful shutdown, optional browser server). Goals store project_name; planner sanitizes names and ties max_attempts to engine config. LLM prompts steer file writes under projects_root. GitHub Actions runs make deps, vet, test, build on Go 1.23 with CGO sqlite deps; multi-stage Dockerfile ships both binaries.

Reviewed by Cursor Bugbot for commit 741df8e. Bugbot is set up for automated code reviews on this repo. Configure here.

Close permission bypasses for all tools, fix Docker argv isolation and goal resume, add tests and DevOps docs, and stop tracking personal config.yaml.

Co-authored-by: Cursor <cursoragent@cursor.com>
@cursor

cursor Bot commented Jul 15, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements a broad “audit roadmap” hardening pass across OctaAI’s tool execution pipeline: tightening permission checks (paths/commands/URLs), improving Docker isolation behavior, adding resumability improvements, introducing project-directory handling, and adding documentation + CI to support safer operation.

Changes:

  • Added centralized path resolution (ResolveProjectPath) and expanded safety policies (command normalization, HTTP SSRF checks, browser domain restrictions, SSH host-key verification).
  • Improved execution reliability: Docker argv preservation, step-view output evaluation, goal resume/checkpoint behavior, and configurable retry/max-attempts.
  • Added operational docs and tooling: SECURITY.md, CONTRIBUTING.md, AGENTS.md, Dockerfile, and GitHub Actions CI; removed personal config.yaml and added it to .gitignore.

Reviewed changes

Copilot reviewed 40 out of 44 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
SECURITY.md Adds security policy, configuration guidance, and threat-model notes.
pkg/tools/ssh.go Enforces known_hosts verification; shell-quotes remote paths for file ops.
pkg/tools/ISSUE.md Removes old internal issue tracking doc from repo.
pkg/tools/git.go Resolves git paths under projects root for clone/init/commit/push.
pkg/tools/filesystem.go Uses centralized project-path resolution for filesystem operations.
pkg/tools/filesystem_test.go Adds filesystem allowlist + read/write behavior tests.
pkg/tools/command.go Normalizes deny-command matching; resolves cwd under projects root.
pkg/tools/command_test.go Adds test for deny-pattern bypass via case/whitespace changes.
pkg/storage/storage.go Adds project_name to persisted goals.
pkg/storage/sqlite.go Migrates goals schema for project_name; updates queries; ignores unmarshal errors.
pkg/plugin/registry.go Small formatting-only adjustment to capability constants.
pkg/planner/replan.go Uses planner-configured max-attempts instead of hardcoded 3.
pkg/planner/project.go Adds project-name sanitization + heuristics for when a goal needs a project directory.
pkg/planner/project_test.go Adds unit tests for project-name sanitization/heuristics.
pkg/planner/planner.go Introduces planner maxAttempts config; persists project name to memory; uses sanitization helper.
pkg/permission/url.go Adds SSRF + browser-domain URL checks (new).
pkg/permission/shellquote.go Adds shell quoting helper for safe remote shell use (new).
pkg/permission/normalize.go Adds command normalization helper for policy matching (new).
pkg/permission/manager.go Hardens tool gating across command/filesystem/git/http/browser/ssh; denies unknown tools.
pkg/permission/manager_test.go Adds unit tests covering core permission behaviors.
pkg/isolation/docker.go Fixes docker workdir computation; preserves argv boundaries via _docker_argv.
pkg/isolation/docker_test.go Adds test ensuring docker wrapping preserves argv and original command string.
pkg/evaluator/evaluator.go Minor formatting-only alignment change.
pkg/evaluator/evaluator_test.go Adds tests for ToolResultEvaluator behaviors.
pkg/engine/step.go Adds ViewWithOutput to evaluate steps with runtime output not yet persisted.
pkg/engine/step_test.go Adds unit test validating ViewWithOutput behavior.
pkg/engine/runner.go Runs permission checks pre-isolation; executes docker argv directly; improves Data handling.
pkg/engine/prompts.go Strengthens system/task prompts around projects root + “write code locally” guidance.
pkg/engine/engine.go Improves resumability/retry loop + checkpoint persistence + evaluation flow refactor.
pkg/engine/checkpoint.go Formatting-only alignment changes.
pkg/config/path_test.go Adds tests for ExpandPath and ResolveProjectPath.
pkg/config/config.go Adds allow_http_hosts; implements ExpandPath + ResolveProjectPath; expands tilde/env on load.
pkg/config/browser.go Adds browser token generation for WebSocket auth (new).
pkg/browser/server.go Requires browser WS token; restricts allowed Origin prefixes; ignores encode errors.
go.mod Promotes websocket/uuid dependencies from indirect to direct.
Dockerfile Adds multi-stage build + runtime image for the daemon.
CONTRIBUTING.md Adds contributor guidance and security-sensitive contribution notes.
config.yaml Removes personal config from repo tracking.
config.example.yaml Adds allow_http_hosts and browser config examples.
cmd/octa-agentd/main.go Adds daemon entrypoint with polling, concurrency, and browser server lifecycle.
cmd/octa-agent/main.go Adds CLI for goals, status/logs, and approvals; supports --project.
AGENTS.md Adds repo/architecture + operational command guide for agent tooling.
.gitignore Stops tracking local config.yaml; tweaks ignored binary paths.
.github/workflows/ci.yml Adds CI workflow (deps/vet/test/build) on PRs and main branches.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread pkg/isolation/docker.go
Comment thread pkg/permission/url.go
Comment thread pkg/permission/url.go Outdated
Comment thread pkg/permission/url.go Outdated
Comment thread pkg/permission/manager.go
MParvin and others added 3 commits July 15, 2026 13:02
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes using high effort and found 5 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 741df8e. Configure here.

Comment thread pkg/engine/engine.go
} else if goal.State != StateExecuting {
if err := e.transitionGoal(goal, StateExecuting); err != nil {
return err
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved goals cannot resume

High Severity

When a goal is approved via octa-agent approve, it enters an IDLE state. ProcessGoal then tries to transition it directly to EXECUTING, but CanTransition only permits IDLE to PLANNING. This invalid state change causes the goal to error continuously and prevents approved actions from running.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 741df8e. Configure here.

Comment thread pkg/permission/url.go
func (m *Manager) CheckBrowserDomain(rawURL string) CheckResult {
if len(m.cfg.Browser.BrowserDomains) == 0 {
return CheckResult{Decision: DecisionAllow}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Empty browser_domains allows all

Medium Severity

CheckBrowserDomain returns allow when browser_domains is empty. With browser automation enabled and the default browser_domains: [], navigate is permitted to any host, so the new domain gate does not restrict navigation unless operators populate the list.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 741df8e. Configure here.

Comment thread pkg/engine/runner.go
var err error

if argv, ok := dockerArgv(execArgs); ok {
result, err = r.runDockerArgv(runCtx, argv)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Injected docker argv bypasses tools

High Severity

Runner.Run runs runDockerArgv whenever tool args contain _docker_argv, without requiring _isolated or stripping caller-controlled keys. LLM JSON can pass a benign command/path for CheckTool then execute arbitrary host argv, bypassing the named tool and Docker isolation when isolation is off or for non-command tools.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 741df8e. Configure here.

Comment thread pkg/engine/engine.go
return fmt.Errorf("failed to get goal: %w", err)
}

switch goal.State {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shared loopCount races goals

Medium Severity

The daemon runs multiple ProcessGoal goroutines on one Engine, but loopCount is a single field reset and incremented per goal. Concurrent goals corrupt each other’s loop counters and checkpoint step indices, causing wrong max-loop exits or evaluation timing.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 741df8e. Configure here.

Comment thread pkg/permission/url.go
}
}

return CheckResult{Decision: DecisionAllow}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HTTP redirect SSRF gap

Medium Severity

CheckURL validates the initial host at permission time, but HTTPTool uses a default http.Client that follows redirects without re-checking. A public URL can redirect to localhost or private addresses after approval.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 741df8e. Configure here.

@MParvin
MParvin merged commit 4cb8b3f into master Jul 15, 2026
2 checks passed
@MParvin
MParvin deleted the cursor/audit-roadmap-implementation branch July 15, 2026 13:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants