avoid-sensitive-query-params

Path
lint/security/avoid-sensitive-query-params
Default
Off, opt in
Origin
Falcon
Rule
134 of 512

Detect explicit secret-bearing URL query keys, not arbitrary occurrences of words such as token in paths, fragments, map values, or prose.

Invalid

example.dartdart
final first = 'https://example.com/?password=secret';
final second = 'http://example.com/path?page=1&access_token=value';
final third = Uri(queryParameters: {'api_key': 'secret'});
final fourth = Uri.https('example.com', '/path', {'client_secret': 'secret'});
final fifth = new Uri(queryParameters: {'refresh_token': 'secret'});
final sixth = Uri.http('example.com', '/', {'PASSWORD': 'secret'});
final seventh = 'https://example.com/?token=$token';
String token = 'secret';

void interpolationPunctuation(String host, String path, String key) {
  final hostQuery = 'https://${host.replaceAll('#', '')}/v1?api_key=$key';
  final pathQuery = 'https://example.com/${path.replaceAll('#', '')}?password=$key';
  final laterQuery = 'https://example.com/?page=${path.replaceAll('', '#')}&token=$key';
}

void literalQueries(String token) {
  final direct = Uri(scheme: 'https', host: 'example.com', query: 'access_token=$token');
  final explicitNew = new Uri(scheme: 'https', host: 'example.com', query: ('page=1&api_key=$token'));
  final interpolation = Uri(query: 'page=${token.replaceAll('', '#')}&password=$token');
  final hashInValue = Uri(query: 'next=/home#top&access_token=$token');
  final adjacentKey = Uri(query: 'page=1&' 'access_token=$token');
}

final encodedUrl = 'https://example.com/?%61ccess_token=value';
final encodedQuery = Uri(query: '%61ccess_token=value');
final encodedSeparator = 'https://example.com/?access%5ftoken=value';
final encodedUppercase = new Uri(query: '%50ASSWORD=value');
Do not put secrets in URL query parameters; use an authorization header or request body.
1final first = 'https://example.com/?password=secret';
Do not put secrets in URL query parameters; use an authorization header or request body.
1final first = 'https://example.com/?password=secret';
2final second = 'http://example.com/path?page=1&access_token=value';
Do not put secrets in URL query parameters; use an authorization header or request body.
2final second = 'http://example.com/path?page=1&access_token=value';
3final third = Uri(queryParameters: {'api_key': 'secret'});
Do not put secrets in URL query parameters; use an authorization header or request body.
3final third = Uri(queryParameters: {'api_key': 'secret'});
4final fourth = Uri.https('example.com', '/path', {'client_secret': 'secret'});
Do not put secrets in URL query parameters; use an authorization header or request body.
4final fourth = Uri.https('example.com', '/path', {'client_secret': 'secret'});
5final fifth = new Uri(queryParameters: {'refresh_token': 'secret'});
Do not put secrets in URL query parameters; use an authorization header or request body.
5final fifth = new Uri(queryParameters: {'refresh_token': 'secret'});
6final sixth = Uri.http('example.com', '/', {'PASSWORD': 'secret'});
Do not put secrets in URL query parameters; use an authorization header or request body.
6final sixth = Uri.http('example.com', '/', {'PASSWORD': 'secret'});
7final seventh = 'https://example.com/?token=$token';
Do not put secrets in URL query parameters; use an authorization header or request body.
10void interpolationPunctuation(String host, String path, String key) {
11 final hostQuery = 'https://${host.replaceAll('#', '')}/v1?api_key=$key';
Do not put secrets in URL query parameters; use an authorization header or request body.
11 final hostQuery = 'https://${host.replaceAll('#', '')}/v1?api_key=$key';
12 final pathQuery = 'https://example.com/${path.replaceAll('#', '')}?password=$key';
Do not put secrets in URL query parameters; use an authorization header or request body.
12 final pathQuery = 'https://example.com/${path.replaceAll('#', '')}?password=$key';
13 final laterQuery = 'https://example.com/?page=${path.replaceAll('', '#')}&token=$key';
Do not put secrets in URL query parameters; use an authorization header or request body.
16void literalQueries(String token) {
17 final direct = Uri(scheme: 'https', host: 'example.com', query: 'access_token=$token');
Do not put secrets in URL query parameters; use an authorization header or request body.
17 final direct = Uri(scheme: 'https', host: 'example.com', query: 'access_token=$token');
18 final explicitNew = new Uri(scheme: 'https', host: 'example.com', query: ('page=1&api_key=$token'));
Do not put secrets in URL query parameters; use an authorization header or request body.
18 final explicitNew = new Uri(scheme: 'https', host: 'example.com', query: ('page=1&api_key=$token'));
19 final interpolation = Uri(query: 'page=${token.replaceAll('', '#')}&password=$token');
Do not put secrets in URL query parameters; use an authorization header or request body.
19 final interpolation = Uri(query: 'page=${token.replaceAll('', '#')}&password=$token');
20 final hashInValue = Uri(query: 'next=/home#top&access_token=$token');
Do not put secrets in URL query parameters; use an authorization header or request body.
20 final hashInValue = Uri(query: 'next=/home#top&access_token=$token');
21 final adjacentKey = Uri(query: 'page=1&' 'access_token=$token');
Do not put secrets in URL query parameters; use an authorization header or request body.
23
24final encodedUrl = 'https://example.com/?%61ccess_token=value';
Do not put secrets in URL query parameters; use an authorization header or request body.
24final encodedUrl = 'https://example.com/?%61ccess_token=value';
25final encodedQuery = Uri(query: '%61ccess_token=value');
Do not put secrets in URL query parameters; use an authorization header or request body.
25final encodedQuery = Uri(query: '%61ccess_token=value');
26final encodedSeparator = 'https://example.com/?access%5ftoken=value';
Do not put secrets in URL query parameters; use an authorization header or request body.
26final encodedSeparator = 'https://example.com/?access%5ftoken=value';
27final encodedUppercase = new Uri(query: '%50ASSWORD=value');

Valid

example.dartdart
final first = 'https://example.com/password';
final second = 'https://example.com/?page=1#token=secret';
final third = Uri(queryParameters: {'page': 'token'});
final fourth = Uri.https('example.com', '/', {'search': 'password'});
final fifth = {'password': 'not a query'};
final sixth = 'The password=secret example is not a URL';
final seventh = 'https://example.com/?token_count=10';
final eighth = Uri.http('example.com', '/token', {'page': '1'});
final fragmentQuery = 'https://app.example.com/#/reset?token=abc';
void shadowed(dynamic Uri) {
  Uri(queryParameters: {'token': 'not a URL'});
  Uri.https('example.com', '/', {'password': 'not a URL'});
  Uri(query: 'token=not-a-network-url');
  Uri(query: '%61ccess_token=not-a-network-url');
}

void interpolationPunctuation(String host, String path, String value) {
  final fragment = 'https://${host.replaceAll('#', '')}/#reset?token=$value';
  final pathOnly = 'https://${host.replaceAll('#', '')}/password=$value';
  final safeQuery = 'https://$host/${path.replaceAll('#', '')}?page=$value';
  final valuePunctuation = 'https://example.com/?page=${value.replaceAll('', '&token=')}';
  final dynamicKey = 'https://example.com/?api_${value}=secret';
  final encodedDynamicKey = 'https://example.com/?%61ccess_${value}=secret';
}

void safeLiteralQueries(String value) {
  final safe = Uri(scheme: 'https', host: 'example.com', query: 'page=$value');
  final fragment = Uri(scheme: 'https', host: 'example.com', fragment: 'token=secret');
  final dynamicQuery = Uri(query: value);
  final dynamicKey = Uri(query: 'api_${value}=secret');
  final dynamicValue = Uri(query: 'page=${value.replaceAll('', '&token=')}');
  query(query: 'token=not-a-url');
  final adjacentValue = Uri(query: 'page=' 'token=not-a-query-key');
}

void query({String? query}) {}

void unrelatedQuery(dynamic client) {
  client.query(query: 'token=not-a-url');
}

final encodedSafeUrl = 'https://example.com/?%70age=1';
final encodedSafeQuery = Uri(query: '%70age=1');
final doubleEncodedUrl = 'https://example.com/?%2561ccess_token=value';
final doubleEncodedQuery = Uri(query: '%2561ccess_token=value');
final malformedEscape = 'https://example.com/?access_token%6=value';
final incompleteEscape = Uri(query: 'access_token%=value');
final invalidHexEscape = Uri(query: '%GGaccess_token=value');
final invalidUtf8Escape = Uri(query: '%FFaccess_token=value');
final encodedMapKey = Uri(queryParameters: {'%61ccess_token': 'value'});
final encodedHttpsMapKey = Uri.https('example.com', '/', {'%61ccess_token': 'value'});
final encodedFragment = 'https://example.com/#%61ccess_token=value';

Configure avoid-sensitive-query-params

Set its severity in falcon.json. See the configuration guide.

falcon.jsonjson
{
  "linter": {
    "rules": {
      "security": {
        "avoid-sensitive-query-params": "error"
      }
    }
  }
}

Or silence one occurrence with a suppression comment; the reason is required.

example.dartdart
// falcon-ignore lint/security/avoid-sensitive-query-params: <reason>