Skip to content

Merge cristian and jackson fixes#75

Open
cmromo wants to merge 34 commits intodevelopfrom
merge-cristian-and-jackson-fixes
Open

Merge cristian and jackson fixes#75
cmromo wants to merge 34 commits intodevelopfrom
merge-cristian-and-jackson-fixes

Conversation

@cmromo
Copy link
Contributor

@cmromo cmromo commented Jan 15, 2026

Add scavenge scan
Fix duplicate vendor ID issues on startup
Fix router and routed devices merge
Frontend and API fixes/improvements
Updated dependencies

Jackson Giles and others added 30 commits November 25, 2025 16:18
Instead of assuming /24 for all discovered devices, now parses the CIDR
prefix from the scanner's configured address (e.g., "192.168.1.12/22:47808")
and uses that prefix length for devices on the local network. Falls back
to /24 only when no local subnet info is available.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Enhances local subnet detection by querying the operating system's
network interfaces (via ifconfig/ip addr) to find the actual netmask
for the scanner's IP address. This ensures accurate subnet detection
even when the configured address uses a different CIDR notation.

- Adds _get_system_interfaces() to parse ifconfig (macOS) and ip addr (Linux)
- Adds _detect_local_subnet() to match scanner IP to system interfaces
- Removes conflicting subnets from config when detected subnet differs
- Falls back to address config CIDR if interface detection fails

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@cmromo cmromo requested a review from acedrew January 15, 2026 19:39

try:
return FileResponse(ttl_filepath, filename=ttl_filename)
except Exception as e:

Check failure

Code scanning / CodeQL

Uncontrolled data used in path expression High

This path depends on a
user-provided value
.

Copilot Autofix

AI 24 days ago

In general, to fix uncontrolled file path usage you should: (1) treat all user-provided path segments as untrusted, (2) resolve them against a known safe root directory using os.path.join and os.path.normpath or os.path.realpath, and (3) verify that the normalized path is still inside the root directory. Optionally, you can further constrain the input so that it does not contain path separators or special characters, turning it into a simple filename rather than an arbitrary path.

For this code, the best minimal fix is to harden get_file_path so that it only ever returns paths strictly within the agent’s data directory, and only for simple filenames. Concretely:

  • Reject file_name values that contain path separators (/ or os.sep), which are not needed here because the endpoint expects “Name of the TTL comparison file to download (including .ttl extension)”, not nested paths.
  • When a matching file is found by os.walk, compute the candidate path, normalize it with os.path.normpath, and verify it is still under folder_path by checking the common prefix via os.path.commonpath([folder_path, full_path]) == folder_path. Only return the path if this check passes.
    These changes are all in Grasshopper/grasshopper/api.py, within get_file_path, and require no new imports because os is already imported.
Suggested changeset 1
Grasshopper/grasshopper/api.py

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/Grasshopper/grasshopper/api.py b/Grasshopper/grasshopper/api.py
--- a/Grasshopper/grasshopper/api.py
+++ b/Grasshopper/grasshopper/api.py
@@ -304,7 +304,15 @@
 
     Raises:
         FileNotFoundError: If the specified folder doesn't exist
+        HTTPException: If an invalid file name is provided
     """
+    # Disallow path separators in the file name to prevent directory traversal
+    if os.path.sep in file_name or (os.path.altsep and os.path.altsep in file_name):
+        raise HTTPException(
+            status_code=status.HTTP_400_BAD_REQUEST,
+            detail="Invalid file name",
+        )
+
     agent_data_path = get_agent_data_path(request)
     folder_path = os.path.join(agent_data_path, folder)
     if not os.path.exists(folder_path):
@@ -314,7 +321,14 @@
 
     for root, dirs, files in os.walk(folder_path):
         if file_name in files:
-            return os.path.join(root, file_name)
+            candidate_path = os.path.normpath(os.path.join(root, file_name))
+            # Ensure the resolved path is still within the expected folder
+            if os.path.commonpath([folder_path, candidate_path]) != folder_path:
+                raise HTTPException(
+                    status_code=status.HTTP_400_BAD_REQUEST,
+                    detail="Invalid file path",
+                )
+            return candidate_path
 
     return None
 
EOF
@@ -304,7 +304,15 @@

Raises:
FileNotFoundError: If the specified folder doesn't exist
HTTPException: If an invalid file name is provided
"""
# Disallow path separators in the file name to prevent directory traversal
if os.path.sep in file_name or (os.path.altsep and os.path.altsep in file_name):
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Invalid file name",
)

agent_data_path = get_agent_data_path(request)
folder_path = os.path.join(agent_data_path, folder)
if not os.path.exists(folder_path):
@@ -314,7 +321,14 @@

for root, dirs, files in os.walk(folder_path):
if file_name in files:
return os.path.join(root, file_name)
candidate_path = os.path.normpath(os.path.join(root, file_name))
# Ensure the resolved path is still within the expected folder
if os.path.commonpath([folder_path, candidate_path]) != folder_path:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Invalid file path",
)
return candidate_path

return None

Copilot is powered by AI and may make mistakes. Always verify output.
acedrew and others added 3 commits January 15, 2026 14:56
Initialize agent_data_path in __init__ instead of onstart() to fix
AttributeError when the web server starts.

The configure() callback can be called before onstart() (per its docstring),
and when webapp is enabled, it spawns _start_server() which accesses
self.agent_data_path - but that was only being set in onstart().

This caused:
  AttributeError: 'Grasshopper' object has no attribute 'agent_data_path'

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
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