fix(#4327): use parameter binding in RemoteVertex.newEdge to prevent SQL injection#4340
Conversation
Up to standards ✅🟢 Issues
|
| Metric | Results |
|---|---|
| Coverage variation | ✅ -7.47% coverage variation |
| Diff coverage | ✅ 100.00% diff coverage |
Coverage variation details
Coverable lines Covered lines Coverage Common ancestor commit (c4cf514) 127540 93469 73.29% Head commit (b58ba41) 159217 (+31677) 104795 (+11326) 65.82% (-7.47%) Coverage variation is the difference between the coverage for the head and common ancestor commits of the pull request branch:
<coverage of head commit> - <coverage of common ancestor commit>
Diff coverage details
Coverable lines Covered lines Diff coverage Pull request (#4340) 5 5 100.00% Diff coverage is the percentage of lines that are covered by tests out of the coverable lines that the pull request added or modified:
<covered lines added or modified>/<coverable lines added or modified> * 100%
NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.
There was a problem hiding this comment.
Code Review
This pull request addresses a SQL injection vulnerability in RemoteVertex.newEdge() by replacing direct string interpolation of property values with named SQL parameters. The feedback correctly points out that in ArcadeDB, named parameters in the query string are prefixed with a colon, but the keys in the parameter map passed to the database should not contain the leading colon. Correcting this implementation detail requires updating both the parameter generation logic in RemoteVertex and the corresponding assertions in the new unit tests.
| final String paramName = ":p" + (i / 2); | ||
|
|
||
| if (i > 0) | ||
| query.append(", "); | ||
|
|
||
| query.append("`"); | ||
| query.append(propName); | ||
| query.append("` = "); | ||
| query.append(paramName); | ||
|
|
||
| if (propValue instanceof String) | ||
| query.append("'"); | ||
| query.append(propValue); | ||
| if (propValue instanceof String) | ||
| query.append("'"); | ||
| params.put(paramName, propValue); |
There was a problem hiding this comment.
In ArcadeDB, named parameters in the SQL query string are prefixed with a colon (e.g., :p0), but the keys in the parameter map passed to the database should not contain the leading colon (e.g., p0). Passing keys with a leading colon in the parameter map will cause the query executor to fail to resolve the parameter values, resulting in binding null or throwing an error at runtime.\n\nTo fix this, define the parameter name without the colon, append the colon to the query string builder, and use the colon-less parameter name as the key in the params map.
final String paramName = "p" + (i / 2);\n\n if (i > 0)\n query.append(", ");\n\n query.append("`");\n query.append(propName);\n query.append("` = :");\n query.append(paramName);\n\n params.put(paramName, propValue);There was a problem hiding this comment.
The :p0 key format is correct for this codebase. NamedParameter.getValue() (engine/.../parser/NamedParameter.java:58-61) tries params.get(":" + key) first before falling back to params.get(key). So map key :p0 resolves correctly for SQL placeholder :p0.
This is also the convention used throughout the existing test suite — for example QueryTest.java uses params.put(":name", "Jay") (colon-prefixed keys). The implementation is intentional and works as-is.
| assertThat(sqlCaptor.getValue()).doesNotContain("O'Brien"); | ||
| assertThat(sqlCaptor.getValue()).contains(":p0"); | ||
| final Map<String, Object> params = (Map<String, Object>) paramsCaptor.getValue(); | ||
| assertThat(params).containsEntry(":p0", "O'Brien"); |
| verify(mockDatabase).command(eq("sql"), sqlCaptor.capture(), paramsCaptor.capture()); | ||
| assertThat(sqlCaptor.getValue()).contains(":p0"); | ||
| final Map<String, Object> params = (Map<String, Object>) paramsCaptor.getValue(); | ||
| assertThat(params).containsEntry(":p0", 42); |
| assertThat(params).containsEntry(":p0", "O'Brien"); | ||
| assertThat(params).containsEntry(":p1", 2023); |
Code ReviewThe core fix is correct and addresses a real SQL injection vulnerability. Here are my findings: Security Fix - CorrectThe parameterized query approach properly eliminates the injection vector. The colon-prefixed key format ( Minor:
|
Code ReviewSummaryThis PR correctly fixes a real SQL injection vulnerability in Positive
Issues1. Docs file should not be committed (blocking)
2. Same injection pattern remains in other methods (non-blocking, worth tracking)The fix covers
These are lower-severity since type/edge-type names are usually developer-controlled, but the pattern is the same. Consider filing a follow-up issue. 3. No integration test against a real server (non-blocking)The test suite mocks Minor / Style
VerdictThe security fix is correct and well-targeted. The committed docs file is the only item that should be addressed before merge. |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #4340 +/- ##
============================================
- Coverage 64.21% 64.11% -0.10%
+ Complexity 448 422 -26
============================================
Files 1645 1645
Lines 127540 127539 -1
Branches 27350 27348 -2
============================================
- Hits 81899 81777 -122
- Misses 34102 34244 +142
+ Partials 11539 11518 -21 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Closes #4327
RemoteVertex.newEdge()was buildingCREATE EDGE … SET prop = 'value'SQL by concatenating property values directly into the query string with no escaping. A value containing a single quote (O'Brien) caused a parse error; a malicious value could inject arbitrary SQL.The fix replaces the string interpolation with named SQL parameters (
:p0,:p1, …) and passes the values via the existingcommand(language, sql, Map<String,Object>)overload. The SQL template now contains only backtick-quoted property names and:pNplaceholders — no user data ever appears in the query string.Test plan
RemoteVertexTest(5 tests) verifies thatcommand()is invoked with a parameterised query and that raw property values — including apostrophes — never appear in the SQL stringmvn test -pl network— 373 tests, 0 failures, 0 errorsnewEdge(type, to, "name", "O'Brien")) and the map form (newEdge(type, to, Map.of("name", "O'Brien"))) are covered