Skip to content

Secure AGE graph queries with parameterization and depth limits#389

Open
Brad-Edwards wants to merge 1 commit intodevfrom
claude/fix-gh-issue-319-ZEU5Q
Open

Secure AGE graph queries with parameterization and depth limits#389
Brad-Edwards wants to merge 1 commit intodevfrom
claude/fix-gh-issue-319-ZEU5Q

Conversation

@Brad-Edwards
Copy link
Copy Markdown
Contributor

Summary

Hardens the AGE graph query service against Cypher injection attacks and denial-of-service attacks by:

  1. Replacing string interpolation with parameterized queries for user-supplied UIDs
  2. Adding depth validation to prevent unbounded graph traversals
  3. Implementing proper escaping for the remaining interpolated values (graph names from config)
  4. Adding input validation at the API layer via Jakarta Bean Validation

Related Issues

Changes

  • AgeGraphService:

    • Added MAX_DEPTH constant (20) to limit graph traversal depth
    • Introduced validateDepth() method to enforce depth constraints in getAncestors() and getDescendants()
    • Refactored getAncestors(), getDescendants(), and findPaths() to use parameterized queries instead of string interpolation for user-supplied UIDs
    • Enhanced escapeCypher() to handle null bytes and backticks (used for identifier escaping in Cypher)
    • Added escapeJson() method for proper JSON string escaping in AGE agtype parameter maps
    • Added ageParams() helper to build AGE parameter maps safely
    • Updated extractUidResults() signature to accept graph name and parameters for parameterized queries
    • Added comprehensive documentation explaining the security rationale for each approach
  • GraphController:

    • Added @Validated annotation to enable method-level validation
    • Added @Min(1) and @Max(20) constraints to depth parameters in getAncestors() and getDescendants()
    • Constraints apply to both endpoints with default value of 10
  • AgeGraphServiceTest:

    • Added DepthValidation nested test class with tests for boundary conditions (depth 0, depth > MAX_DEPTH, depth = MAX_DEPTH)
    • Added EscapeCypher nested test class with unit tests for escaping logic (backslash, single quote, null bytes, backticks)
    • Updated existing query verification tests to expect parameterized query calls
  • GraphControllerTest:

    • Added tests for HTTP 400 responses when depth exceeds 20 or is zero in both ancestors and descendants endpoints

Test Plan

  • Unit tests added for depth validation and escaping logic
  • Integration tests updated to verify parameterized query behavior
  • API layer tests verify constraint validation returns 400 for invalid depth values

Checklist

  • Code follows project coding standards
  • No business logic in API layer (validation only)
  • Domain layer has no framework imports
  • CHANGELOG.md should be updated

https://claude.ai/code/session_01WsTk6SDzcHxfwD35BxT5q5

…aphService

- Use AGE parameterized queries (agtype params) for uid values in getAncestors,
  getDescendants, and findPaths, eliminating Cypher injection from user input
- Use JDBC ? placeholder for graph name (replaces string interpolation)
- Add MAX_DEPTH = 20 constant and validateDepth() to prevent DoS via unbounded
  graph traversals; illegal argument exception thrown for depth outside [1, 20]
- Improve escapeCypher() with null-byte stripping and backtick escaping for
  materializeGraph() where AGE multi-property parameterization is not practical
- Add escapeJson() helper for safe JSON building of AGE agtype param maps
- Add @validated + @min(1) @max(20) on depth params in GraphController to return
  HTTP 400 for out-of-range requests before they reach the service layer
- Add tests: depth bounds validation, escapeCypher edge cases, controller 400s

Closes #319

https://claude.ai/code/session_01WsTk6SDzcHxfwD35BxT5q5
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