Skip to content

sec(credentials): validate gcp_client_email + aws_web_identity_token_file + aws_role_arn at API boundary (closes #405, #403, #413) - #504

Merged
cristim merged 2 commits into
feat/multicloud-web-frontendfrom
sec/credential-input-validation
May 20, 2026
Merged

sec(credentials): validate gcp_client_email + aws_web_identity_token_file + aws_role_arn at API boundary (closes #405, #403, #413)#504
cristim merged 2 commits into
feat/multicloud-web-frontendfrom
sec/credential-input-validation

Conversation

@cristim

@cristim cristim commented May 19, 2026

Copy link
Copy Markdown
Member

Summary

Test plan

  • go test ./internal/api/... passes (1087 tests)
  • POST /api/accounts with gcp_client_email: "foo@bar.com/../../v1/projects/-/serviceAccounts/attacker@evil.com" returns 400
  • POST /api/accounts with aws_web_identity_token_file: "/proc/self/environ" returns 400
  • POST /api/accounts with aws_role_arn: "not-an-arn" returns 400
  • Valid values for all three fields are still accepted

Summary by CodeRabbit

  • New Features

    • Enhanced validation of cloud provider account credentials (GCP and AWS) including stricter format verification and security checks to prevent configuration errors and unauthorized file system access.
  • Tests

    • Comprehensive new test coverage for credential validation across multiple scenarios including edge cases, malformed inputs, and security-related conditions.

Review Change Stack

…n_file at API boundary

Add format validation for three credential fields at the handler boundary
so invalid values are rejected with HTTP 400 before reaching the database
or credential resolver.

- gcp_client_email: must match the GCP service-account email regex
  (name@project.iam.gserviceaccount.com); blocks URL path injection into
  the SA impersonation URL in BuildGCPFederatedCredential (closes #405)
- aws_web_identity_token_file: restricted to /var/run/secrets/eks... and
  /var/run/secrets/kubernetes.io/... prefixes; path traversal sequences
  rejected; blocks arbitrary host file reads via STS (closes #403)
- aws_role_arn: must match the IAM role ARN format for aws/aws-cn/aws-us-gov
  partitions; blocks malformed strings reaching stscreds (closes #413)

All three helpers live in validation.go alongside the existing validators.
108 new test cases cover the attack vectors from each issue plus happy paths.
@cristim cristim added triaged Item has been triaged priority/p1 Next up; this sprint severity/high Significant harm urgency/this-sprint Within the current sprint impact/many Affects most users effort/s Hours type/security Security finding labels May 19, 2026
@coderabbitai

coderabbitai Bot commented May 19, 2026

Copy link
Copy Markdown
Contributor

Warning

Rate limit exceeded

@cristim has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 8 minutes and 9 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9a35926f-8c42-42fa-b993-276f7d98c682

📥 Commits

Reviewing files that changed from the base of the PR and between a1b4850 and bc90311.

📒 Files selected for processing (2)
  • internal/api/validation.go
  • internal/api/validation_test.go
📝 Walkthrough

Walkthrough

Adds three credential field validators to the API layer before account persistence: GCP service account email format validation, AWS IAM role ARN format validation, and AWS web identity token file path validation with prefix allowlisting and path-traversal blocking. Handler integration calls these validators during account creation and update.

Changes

Credential Field Validation for Cloud Accounts

Layer / File(s) Summary
Credential validation primitives and tests
internal/api/validation.go, internal/api/validation_test.go
Adds regex patterns and allowlists for GCP email format ([a-z][a-z0-9-]{4,28}[a-z0-9]@[a-z][a-z0-9-]+\.iam\.gserviceaccount\.com), AWS ARN format across partitions, and AWS token-file paths restricted to allowed prefixes (/var/run/secrets/, /run/secrets/). Three new validators return 400 errors for non-matching non-empty values and block .. path traversal. Comprehensive test coverage includes valid/invalid formats, email/ARN edge cases, and token-file security boundaries.
GCP auth handler integration
internal/api/handler_accounts.go
Handler now invokes validateGCPClientEmail during GCP auth-mode validation, preventing invalid service account emails from reaching storage.
AWS auth handler integration
internal/api/handler_accounts.go
Handler now invokes validateAWSRoleARN and validateAWSWebIdentityTokenFile during AWS auth-mode validation, enforcing ARN format and path-prefix restrictions before persistence.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • LeanerCloud/CUDly#146: Updates AWS role_arn validation in the onboarding flow; overlaps with this PR's AWS role ARN format validator in validateAWSAuthMode.

Poem

🐰 With email patterns matched and paths contained,
The rabbit guards each credential field from stray.
No traversal tricks shall breach the API gate,
No attacker-ARNs can lead hearts astray today! 🔐

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the security validation additions for credential fields (gcp_client_email, aws_web_identity_token_file, aws_role_arn) at the API boundary and correctly references the three closed issues.
Linked Issues check ✅ Passed All code changes directly address the linked issues: validateGCPClientEmail prevents GCP email injection (#405), validateAWSWebIdentityTokenFile restricts file paths to safe prefixes (#403), validateAWSRoleARN enforces ARN format (#413), and validators are wired into the request handlers.
Out of Scope Changes check ✅ Passed All changes are scoped to the three security validation objectives: three new validators in validation.go, their integration into handler_accounts.go, and corresponding test coverage in validation_test.go with no unrelated modifications.
Docstring Coverage ✅ Passed Docstring coverage is 90.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch sec/credential-input-validation

Comment @coderabbitai help to get the list of available commands and usage tips.

@cristim

cristim commented May 19, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@cristim cristim changed the title sec(credentials): validate gcp_client_email + aws_web_identity_token_file at API boundary (closes #405, #403) sec(credentials): validate gcp_client_email + aws_web_identity_token_file + aws_role_arn at API boundary (closes #405, #403, #413) May 19, 2026
@coderabbitai

coderabbitai Bot commented May 19, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
internal/api/validation_test.go (1)

361-363: ⚡ Quick win

Assert client-error type explicitly in negative-path cases.

The current conditional check can pass even if the error is not a ClientError. Make the type assertion mandatory before checking code 400, so these tests enforce the API contract.

Proposed hardening pattern (apply in all 3 tests)
-				if ce, ok := IsClientError(err); ok {
-					assert.Equal(t, 400, ce.code)
-				}
+				ce, ok := IsClientError(err)
+				if assert.True(t, ok, "expected ClientError") {
+					assert.Equal(t, 400, ce.code)
+				}

Also applies to: 397-399, 433-435

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/api/validation_test.go` around lines 361 - 363, The tests currently
use a conditional type-check pattern "if ce, ok := IsClientError(err); ok {
assert.Equal(t, 400, ce.code) }" which allows a non-failing path when the error
is not a ClientError; change each of these (the occurrences around IsClientError
in internal/api/validation_test.go) to make the type-assertion mandatory: first
assert or require that IsClientError(err) returns true (e.g., require.True(t,
ok) or assert.True(t, ok)), then use the asserted value (ce) to assert the code
equals 400; update the three places noted (around lines 361-363, 397-399,
433-435) to follow this pattern so the test fails if err is not a ClientError.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/api/validation.go`:
- Line 38: Replace the permissive awsRoleARNRegex with a stricter pattern that
only allows valid IAM role path/name characters: update the awsRoleARNRegex
variable to use a regex like
^arn:(aws|aws-cn|aws-us-gov):iam::[0-9]{12}:role\/(?:[A-Za-z0-9+=,.@_-]+\/)*[A-Za-z0-9+=,.@_-]+$
so that the part after "role/" accepts only IAM-safe characters (alphanumerics
and +=,.@_-) and proper path segments, preventing whitespace or other invalid
characters from passing validation (update the awsRoleARNRegex declaration in
internal/api/validation.go accordingly).

---

Nitpick comments:
In `@internal/api/validation_test.go`:
- Around line 361-363: The tests currently use a conditional type-check pattern
"if ce, ok := IsClientError(err); ok { assert.Equal(t, 400, ce.code) }" which
allows a non-failing path when the error is not a ClientError; change each of
these (the occurrences around IsClientError in internal/api/validation_test.go)
to make the type-assertion mandatory: first assert or require that
IsClientError(err) returns true (e.g., require.True(t, ok) or assert.True(t,
ok)), then use the asserted value (ce) to assert the code equals 400; update the
three places noted (around lines 361-363, 397-399, 433-435) to follow this
pattern so the test fails if err is not a ClientError.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 020c2690-2485-44e1-b702-b0c1af72a17f

📥 Commits

Reviewing files that changed from the base of the PR and between 4220ef6 and a1b4850.

📒 Files selected for processing (3)
  • internal/api/handler_accounts.go
  • internal/api/validation.go
  • internal/api/validation_test.go

Comment thread internal/api/validation.go Outdated
Resolves CodeRabbit feedback on PR #504. The previous awsRoleARNRegex
accepted any non-empty suffix after `:role/`, which let whitespace,
newlines, and HTML metachars pass validation and reach downstream
consumers (stscreds.NewAssumeRoleProvider and any caller that logs or
echoes the value). The role name and path segments are now restricted
to the IAM-permitted character class `[A-Za-z0-9+=,.@_-]`, with optional
path segments separated by `/`. A trailing slash (empty role name) is
also rejected.

Also tighten the validation_test.go assertions on negative paths so
they fail when the returned error is not a ClientError, rather than
silently passing the type guard.

No behaviour change for valid ARNs.
@cristim

cristim commented May 19, 2026

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented May 19, 2026

Copy link
Copy Markdown
Contributor
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

effort/s Hours impact/many Affects most users priority/p1 Next up; this sprint severity/high Significant harm triaged Item has been triaged type/security Security finding urgency/this-sprint Within the current sprint

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant