Skip to content

fix(security): Improve SQL parameterization for geodatasets + comprehensive tests#933

Merged
tariqksoliman merged 32 commits intoNASA-AMMOS:developmentfrom
JPL-Devin:development
Apr 10, 2026
Merged

fix(security): Improve SQL parameterization for geodatasets + comprehensive tests#933
tariqksoliman merged 32 commits intoNASA-AMMOS:developmentfrom
JPL-Devin:development

Conversation

@tariqksoliman
Copy link
Copy Markdown
Member

With Devin

JPL-Devin#27

devin-ai-integration bot and others added 30 commits April 1, 2026 23:04
…tion

- Configure detect-secrets with standard plugin set (AWS, Azure, GitHub, JWT, etc.)
- Exclude src/external/, node_modules/, build/, .git/ from scanning
- Matches pattern used by atlas repo's .secrets.baseline
- Enables CI secret detection workflows to skip known false positives

Co-Authored-By: tariq.k.soliman <tariq.k.soliman@jpl.nasa.gov>
- Mirrors atlas repo's secrets-detection.yaml workflow
- Uses NASA-AMMOS/slim-detect-secrets for scanning
- Triggers on push/PR to development branch
- Excludes src/external/, node_modules/, build/, .git/ paths
- Compares scan results against .secrets.baseline to detect new secrets
- Fails CI if new secrets are detected, with remediation instructions

Co-Authored-By: tariq.k.soliman <tariq.k.soliman@jpl.nasa.gov>
Run detect-secrets scan against the repo with the same exclude patterns
as the CI workflow. All 7 findings are placeholder/sample values marked
as is_secret=false:

- sample.env: SECRET=aSecretKey, DB_PASS=password (sample config)
- API/logger.js: placeholder secret keyword
- sds/unity/terraform/terraform.tfvars: sample credentials
- tests/unit/*.spec.js: test fixture secrets

This ensures the CI workflow's diff check passes — only genuinely new
secrets introduced in future commits will fail the build.

Co-Authored-By: tariq.k.soliman <tariq.k.soliman@jpl.nasa.gov>
Co-Authored-By: tariq.k.soliman <tariq.k.soliman@jpl.nasa.gov>
…aseline

chore(security): Add .secrets.baseline and CI secrets detection workflow
…ent injection

- Fix geometry.type filter: use Sequelize replacement parameters instead of string interpolation
- Fix property key interpolation: use replacement parameter instead of escaped single quotes
- Fix timeProp temporal filter: use replacement parameter instead of string concatenation
- Add SQL injection security tests for filter keys, values, geometry.type, timeProp, sortBy
- Add functional regression tests for all filter types (equality, numeric, IN, LIKE, IS NULL, geometry.type, grouped, pagination, spatial, sortBy)
- Add CRUD + filter integration test to verify parameterized queries return correct results

Co-Authored-By: tariq.k.soliman <tariqksoliman@gmail.com>
…icts

Co-Authored-By: tariq.k.soliman <tariqksoliman@gmail.com>
…ion-filesutils

fix(security): Parameterize SQL queries in Draw/Files filters to prevent injection
…e status

The parameterized query fix safely handles special characters in field
names (like semicolons), so the server correctly returns 'success' with
no matching rows rather than 'failure'. Updated the test assertion to
accept both outcomes since either is a valid non-500 response.

Co-Authored-By: tariq.k.soliman <tariqksoliman@gmail.com>
…eld-test

fix(test): update invalid field name test to accept success or failure status
…ements in filesutils.js

- Rename geometry.type placeholders to geom_type_${idx} for consistency
- Rename propKey placeholder variable to propKeyPlaceholder for clarity
- Remove manual quote escaping (.replaceAll("'", "''")) since Sequelize
  replacements handle escaping automatically (prevents double-escaping)
- Add E2E filter injection tests to draw.spec.js (6 new test cases)
- Add draw getfile filter tests to sql-injection.spec.js (12 new test cases)
- Add filter field name regex validation unit tests (3 new test cases)

Resolves SonarQube S3649 SQL injection vulnerability.

Co-Authored-By: tariq.k.soliman <tariqksoliman@gmail.com>
Co-Authored-By: tariq.k.soliman <tariqksoliman@gmail.com>
…ion-filesutils

Devin/1775781632 fix sql injection filesutils
…injection tests

- Fix 2a: Add dynamic column name validation for startProp/endProp in
  /aggregations and /intersect endpoints using describeTable()
- Fix 2b: Remove unused startProp/endProp replacement keys from query objects
- Fix 3a: Add filesutils-sql-injection.spec.js with tests for filter field
  names, geometry.type injection, timeProp sanitization, and filter values
- Fix 3b: Add SQL injection tests to geodatasets.spec.js for /aggregations,
  /intersect, and /get endpoints with malicious startProp/endProp
- Fix 3c: Extend sql-injection-prevention.spec.js with edge cases for
  forceAlphaNumUnder (SQL keywords, OR injection, backticks, brackets)

Co-Authored-By: tariq.k.soliman <tariqksoliman@gmail.com>
…ddir

Replace user-tainted urlSplit with already-validated resolvedPath when
constructing the fs.readdir argument in queryTilesetTimes. This breaks
the taint chain that SonarQube tracks from req.query.path to fs.readdir
while maintaining identical behavior (resolvedPath is derived from the
same path.join(rootDir, decodedUrl) that urlSplit was).

Co-Authored-By: tariq.k.soliman <tariqksoliman@gmail.com>
… rootDir

Address Devin Review feedback: if the MMGIS installation directory
happened to contain '_time_' in its path, resolvedPath.split('_time_')
would split at the wrong occurrence. Use indexOf with allowedBase.length
offset to find the _time_ marker only within the URL portion of the
resolved path.

Co-Authored-By: tariq.k.soliman <tariqksoliman@gmail.com>
…ing server)

Co-Authored-By: tariq.k.soliman <tariqksoliman@gmail.com>
…assertions

- Apply same column allowlist validation to /get endpoint as /intersect and /aggregations
- Make /get .then() callback async for await support
- Remove unused startProp/endProp from /get replacements object
- Remove response.json() calls from filesutils tests (server returns HTML not JSON)

Co-Authored-By: tariq.k.soliman <tariqksoliman@gmail.com>
…taint-chain

fix(security): break SonarQube taint chain in queryTilesetTimes fs.readdir
devin-ai-integration bot and others added 2 commits April 10, 2026 02:06
When a geodataset has no time columns configured (start_time and end_time
are both NULL), the time filter was excluding all rows. Add a third OR
condition (start_time IS NULL AND end_time IS NULL) so features without
temporal data are always included in results.

Applies to /get, /intersect, and /aggregations endpoints.

Co-Authored-By: tariq.k.soliman <tariqksoliman@gmail.com>
…hardening

fix(security): SQL injection hardening for geodatasets + comprehensive tests
@tariqksoliman tariqksoliman self-assigned this Apr 10, 2026
@tariqksoliman tariqksoliman merged commit 49de998 into NASA-AMMOS:development Apr 10, 2026
4 of 7 checks passed
@github-project-automation github-project-automation bot moved this to Done in MMGIS Apr 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant