aws-quicksight-datasource-exposes-credential
A QuickSight data source that stores database credentials (CredentialPair / API key) exposes those credentials - readable by the QuickSight service and potentially exfiltrable by updating the data source endpoint.
match
A conjunctive graph pattern. Variables (?x) bind node ids; every clause must hold.
where
node_type(?datasource) ==
GenericData
?datasource.provider_type == 'AWS::QuickSight::DataSource'
?datasource.credential_type in ['USERNAME_PASSWORD', 'API_KEY', 'CREDENTIAL_PAIR']
emit
| source type | Data |
|---|---|
| target type | Credential |
| source | ?datasource |
| target | ?secret |
| conditions | service_state |
| state logic | CONDITIONAL(service_state) when the data source status cannot be confirmed as CREATION_SUCCESSFUL (status is absent/uncollected/UNKNOWN). ACTIVE only when the data source is explicitly in CREATION_SUCCESSFUL state and configured with a non-AWS-IAM credential type (CredentialPair / API key). BLOCKED when credential type is IAM (no stored credential; QuickSight uses the service role instead). |
Narrative
QuickSight data source {datasource.name} stores {secret.credential_type} credentials for its backend. These credentials are held internally by QuickSight and used to authenticate to the data source on every query and refresh.
Raw rule rules/derived/aws/quicksight.yaml
id: aws-quicksight-datasource-exposes-credential
emits: ExposesCredential
description: "A QuickSight data source that stores database credentials (CredentialPair / API key) exposes\
\ those credentials \u2014 readable by the QuickSight service and potentially exfiltrable by updating\
\ the data source endpoint."
match:
- - datasource: null
- ContainsSecret
- secret: null
where:
- node_type(?datasource) == GenericData
- ?datasource.provider_type == 'AWS::QuickSight::DataSource'
- ?datasource.credential_type in ['USERNAME_PASSWORD', 'API_KEY', 'CREDENTIAL_PAIR']
emit:
source_type: Data
target_type: Credential
source: ?datasource
target: ?secret
permissions: []
conditions:
- service_state
state_logic: CONDITIONAL(service_state) when the data source status cannot be confirmed as CREATION_SUCCESSFUL
(status is absent/uncollected/UNKNOWN). ACTIVE only when the data source is explicitly in CREATION_SUCCESSFUL
state and configured with a non-AWS-IAM credential type (CredentialPair / API key). BLOCKED when credential
type is IAM (no stored credential; QuickSight uses the service role instead).
confidence: min(contributing_confidences) * 0.85
derived_from:
- aws-quicksight-datasource-contains-secret
false_positive_note: "QuickSight does NOT expose plaintext credentials via DescribeDataSource API \u2014\
\ the credential fields are redacted. This edge expresses that the credentials ARE stored and used\
\ by the service (they can be exfiltrated indirectly via UpdateDataSource endpoint replacement \u2014\
\ see rule aws-quicksight-ssrf-datasource-cred). Do NOT emit for IAM-credential data sources (S3,\
\ Athena, Redshift via IAM) \u2014 those use the QuickSight service role, not stored credentials;\
\ the role's access is modeled via CanReadData. credential-chains.yaml read-secret-yields-identity\
\ can only fire when CredentialsFor(secret -> DB identity) is also emitted by the explicit normalization."
narrative: QuickSight data source {datasource.name} stores {secret.credential_type} credentials for
its backend. These credentials are held internally by QuickSight and used to authenticate to the data
source on every query and refresh.