Skip to content
Open
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
7 changes: 7 additions & 0 deletions guarddog/sandbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,13 @@ def _get_common_read_paths() -> list[str]:

candidates = [sys.prefix, sys.base_prefix, "/usr", "/lib"]

# Current working directory: sandboxed scanning runs from wherever the
# user's shell happens to be, and tarsafe calls os.getcwd() during
# extraction to bound path-traversal checks. Without READ access here
# that call fails with PermissionError, which tarfile misreports as
# "not a gzip file".
candidates.append(os.getcwd())

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Do not expose the entire launch directory

When GuardDog is launched from a sensitive directory such as the user's home or a repository root, allow_path grants recursive READ access to that entire tree in both apply_sandbox and extract_sandboxed. This defeats the documented filesystem isolation for archive/parser exploits and can expose credentials or source files unrelated to the scan; satisfy tarsafe's getcwd() requirement by changing into an already-allowed temporary/extraction directory rather than globally allowlisting the caller's cwd.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Handle an unavailable current directory

When the process's working directory has been renamed or deleted after startup, os.getcwd() raises FileNotFoundError, so every sandboxed scan now fails while constructing the common allowlist—even remote scans whose inputs and temporary directories remain valid. Catch OSError here and omit the cwd, or obtain it only in the archive path that actually requires it.

Useful? React with 👍 / 👎.


# SSL certificate directories: pygit2 initializes OpenSSL at import time and
# reads the system CA bundle. On Linux (Landlock), only explicitly listed paths
# are readable — unlike macOS (Seatbelt) which includes system paths by default.
Expand Down
7 changes: 7 additions & 0 deletions tests/core/test_sandbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,13 @@ def test_common_read_paths_includes_sys_prefix(self):
paths = _get_common_read_paths()
assert any(p == os.path.realpath(sys.prefix) for p in paths)

def test_common_read_paths_includes_cwd(self):
"""os.getcwd() must be readable: tarsafe calls it during extraction
to bound path-traversal checks, and the sandbox otherwise denies it
with a PermissionError that tarfile misreports as corrupt data."""
paths = _get_common_read_paths()
assert os.path.realpath(os.getcwd()) in paths


class TestPathVariants:
def test_plain_path_returns_single_entry(self):
Expand Down
Loading