Skip to content

fix(a2a): add type validation for email extraction in list_agents_for_user#4699

Open
bogdanmariusc10 wants to merge 4 commits into
mainfrom
4670-bug-root-cause-investigation---user-dict-passed-instead-of-email-string-to-get_rpc_filter_context
Open

fix(a2a): add type validation for email extraction in list_agents_for_user#4699
bogdanmariusc10 wants to merge 4 commits into
mainfrom
4670-bug-root-cause-investigation---user-dict-passed-instead-of-email-string-to-get_rpc_filter_context

Conversation

@bogdanmariusc10
Copy link
Copy Markdown
Collaborator

@bogdanmariusc10 bogdanmariusc10 commented May 11, 2026

🔗 Related Issue

Closes #4670


📝 Summary

Root Cause Fix: Adds type validation for email extraction in the deprecated list_agents_for_user() method to prevent passing dict objects to SQL queries.

Problem: The method was extracting email from user_info dict without validating it was a string. When the "email" key contained a nested dict or other object, it was passed directly to SQL queries, causing:

Error binding parameter 1: type 'dict' is not supported

Solution: Added type validation immediately after email extraction (lines 1118-1126). If a non-string is detected:

  • Logs a warning with type information for debugging
  • Uses empty string (public-only access, fail-safe)
  • Prevents SQL binding error

Defense-in-Depth: This fix complements the defensive validation added in PR #4637 at the get_rpc_filter_context() level. Both layers follow security best practices.

Why Other Code Paths Are Safe:

  • Other service methods accept user_email: str parameters, not dicts
  • The get_user_email() helper already has proper type validation
  • Endpoint handlers receive validated dicts from get_current_user_with_permissions()

🏷️ Type of Change

  • Bug fix
  • Feature / Enhancement
  • Documentation
  • Refactor
  • Chore (deps, CI, tooling)
  • Other (describe below)

🧪 Verification

Check Command Status
Lint suite make lint ✅ Pass
Unit tests make test ✅ Pass
Coverage ≥ 80% make coverage ✅ Pass

✅ Checklist

  • Code formatted (make black isort pre-commit)
  • Tests added/updated for changes
  • Documentation updated (if applicable)
  • No secrets or credentials committed

📓 Notes

Investigation Methodology:

  1. Traced error from TeamManagementService.get_user_teams() back through call chain
  2. Examined all 31 calls to get_user_teams() across the codebase
  3. Searched for all 74 occurrences of .get("email") patterns
  4. Identified list_agents_for_user() as the only vulnerable code path

Code Change (lines 1118-1126):

# BEFORE (buggy):
user_email = user_info.get("email", "")

# AFTER (fixed):
email_value = user_info.get("email", "")
# SECURITY: Ensure email is a string, not a nested dict or other object
# This prevents passing entire user dicts to SQL queries
if isinstance(email_value, str):
    user_email = email_value
else:
    logger.warning(
        f"list_agents_for_user: user_info['email'] is non-string type {type(email_value).__name__}, using empty string"
    )
    user_email = ""

Security Consideration: Setting user_email to empty string when type validation fails results in public-only access, which is the secure default per the two-layer security model documented in AGENTS.md.

Test Coverage: PR #4637 added comprehensive test coverage for the symptom at the get_rpc_filter_context() level. This root cause fix ensures those tests continue to pass, but warning logs should not fire in normal operation since the issue is now prevented at the source.

Added tests for type validation logic: /tests/unit/mcpgateway/services/test_a2a_service.py::TestListAgentsForUserTypeValidation

…_user

Root cause fix for issue #4670. The deprecated list_agents_for_user() method
was extracting email from user_info dict without validating it was a string.
If the 'email' key contained a nested dict or other object, it would be passed
directly to SQL queries, causing:

  Error binding parameter 1: type 'dict' is not supported

This fix adds type validation immediately after email extraction, logging a
warning and using empty string (public-only access) if a non-string is detected.

This complements the defensive fix in PR #4637 which added validation at the
get_rpc_filter_context() level. Both layers of validation follow defense-in-depth
security principles.

Closes #4670

Signed-off-by: Bogdan-Marius-Catanus <[email protected]>
@bogdanmariusc10 bogdanmariusc10 added the bug Something isn't working label May 11, 2026
@bogdanmariusc10 bogdanmariusc10 added a2a Support for A2A protocol api REST API Related item labels May 11, 2026
Signed-off-by: Bogdan-Marius-Catanus <[email protected]>
Bogdan-Marius-Catanus added 2 commits May 11, 2026 14:18
Signed-off-by: Bogdan-Marius-Catanus <[email protected]>
Signed-off-by: Bogdan-Marius-Catanus <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

a2a Support for A2A protocol api REST API Related item bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG]: Root cause investigation - user dict passed instead of email string to get_rpc_filter_context()

1 participant