1-SEC contributors · Reviewed · Module: ai_containment
Connected-Account Unlinking: Local Tracker and Provider Revocation
The optional Token Vault component processes connected-account events.
What 1-SEC checks
The optional Token Vault component processes connected-account events. An unlink event calls the account tracker with user and connection identifiers; account tracking is part of the local monitoring and authorization context used by this integration.
Required telemetry and context
Relevant input events: connected_account_link, connected_account_unlink, connected_account_usage. Use a trusted producer at the real application boundary.
user_idconnectionagent_id where applicable
Field names above describe relevant context, not a complete API request. Consult the current event contract for envelope and detail requirements. Preserve booleans, numbers, and strings as the receiving handler expects them. Agent-provided text cannot independently verify identity or authorization.
Deployment, prevention, and response
Perform provider-side revocation through the identity/provider service and invalidate application credential caches. Then verify both the local state and an attempted use through the real authorization path. Keep connection/user identifiers bound to the authenticated principal rather than model text.
Record the source event, affected agent/host, actual target, policy decision, and response result. Review enforcement configuration separately from detection. A recommendation, selected action, dry-run record, and completed action are different outcomes.
Reproduce the source fixtures
From a checkout of the linked 1-SEC source revision, run the selected fixtures with the repository's Go toolchain. These commands run tests; they do not execute a real attack against your systems.
go test ./internal/modules/tokenvault -run '^(TestConnectedAccountTracker|TestEventTypes)$' -count=1The referenced source fixtures ran in the selected local package suites. Helper tests and synthetic events establish only the assertions shown, not production prevention or framework compatibility.
TestConnectedAccountTracker
Full fixture and assertions — run in its original package with its helpers.
func TestConnectedAccountTracker(t *testing.T) {
cat := NewConnectedAccountTracker()
cat.RecordLink("user-1", "google-oauth2", "openid profile email")
cat.RecordLink("user-1", "github", "repo read:user")
if cat.AccountCount() != 2 {
t.Errorf("expected 2 accounts, got %d", cat.AccountCount())
}
// Agent not authorized yet
if cat.IsAgentAuthorized("user-1", "google-oauth2", "agent-1") {
t.Error("agent should not be authorized before delegation")
}
// Authorize agent
cat.AuthorizeAgent("user-1", "google-oauth2", "agent-1", "openid profile", time.Now().Add(time.Hour))
if !cat.IsAgentAuthorized("user-1", "google-oauth2", "agent-1") {
t.Error("agent should be authorized after delegation")
}
// Different connection — not authorized
if cat.IsAgentAuthorized("user-1", "github", "agent-1") {
t.Error("agent should not be authorized for unlinked connection")
}
if cat.AgentCount() != 1 {
t.Errorf("expected 1 authorized agent, got %d", cat.AgentCount())
}
// Unlink revokes agent authorization
cat.RecordUnlink("user-1", "google-oauth2")
if cat.IsAgentAuthorized("user-1", "google-oauth2", "agent-1") {
t.Error("agent authorization should be revoked after unlink")
}
if cat.AccountCount() != 1 {
t.Errorf("expected 1 account after unlink, got %d", cat.AccountCount())
}
}TestEventTypes
Full fixture and assertions — run in its original package with its helpers.
func TestEventTypes(t *testing.T) {
types := EventTypes()
if len(types) == 0 {
t.Fatal("expected non-empty event types")
}
required := []string{
"token_exchange", "connected_account_link", "connected_account_unlink",
"oauth_grant",
}
typeSet := make(map[string]bool, len(types))
for _, et := range types {
typeSet[et] = true
}
for _, r := range required {
if !typeSet[r] {
t.Errorf("missing required event type: %s", r)
}
}
}Tuning, evaluation, and coverage limits
Updating local state is not proof that every already-issued credential was revoked at the external provider. The component is opt-in and needs the correct event producer. A missed unlink event or a separate credential cache can leave the local view incomplete.
Evaluate this behavior with representative authorized activity and a controlled known-positive case. Investigate the exact rule, inputs, and state before suppressing an alert. Do not assume a hard-coded heuristic is a configurable setting. Measure your own deployment; the source fixtures do not establish a benchmark, detection rate, compliance certification, or incident-prevention claim.