datadog 2.21.0 → 2.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +48 -1
  3. data/ext/LIBDATADOG_DEVELOPMENT.md +60 -0
  4. data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.c +1 -1
  5. data/ext/libdatadog_api/ddsketch.c +106 -0
  6. data/ext/libdatadog_api/init.c +3 -0
  7. data/ext/libdatadog_api/library_config.c +35 -27
  8. data/ext/libdatadog_api/process_discovery.c +19 -13
  9. data/ext/libdatadog_extconf_helpers.rb +1 -1
  10. data/lib/datadog/appsec/api_security/endpoint_collection/grape_route_serializer.rb +26 -0
  11. data/lib/datadog/appsec/api_security/endpoint_collection/rails_collector.rb +59 -0
  12. data/lib/datadog/appsec/api_security/endpoint_collection/rails_route_serializer.rb +29 -0
  13. data/lib/datadog/appsec/api_security/endpoint_collection/sinatra_route_serializer.rb +26 -0
  14. data/lib/datadog/appsec/api_security/endpoint_collection.rb +10 -0
  15. data/lib/datadog/appsec/assets/waf_rules/README.md +30 -36
  16. data/lib/datadog/appsec/assets/waf_rules/recommended.json +359 -4
  17. data/lib/datadog/appsec/assets/waf_rules/strict.json +43 -2
  18. data/lib/datadog/appsec/compressed_json.rb +1 -1
  19. data/lib/datadog/appsec/configuration/settings.rb +9 -0
  20. data/lib/datadog/appsec/contrib/active_record/instrumentation.rb +3 -1
  21. data/lib/datadog/appsec/contrib/excon/ssrf_detection_middleware.rb +3 -2
  22. data/lib/datadog/appsec/contrib/faraday/ssrf_detection_middleware.rb +3 -1
  23. data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +3 -1
  24. data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +9 -4
  25. data/lib/datadog/appsec/contrib/rack/request_middleware.rb +5 -1
  26. data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +7 -2
  27. data/lib/datadog/appsec/contrib/rails/patcher.rb +30 -0
  28. data/lib/datadog/appsec/contrib/rest_client/request_ssrf_detection_patch.rb +3 -1
  29. data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +10 -4
  30. data/lib/datadog/appsec/event.rb +12 -14
  31. data/lib/datadog/appsec/metrics/collector.rb +19 -3
  32. data/lib/datadog/appsec/metrics/telemetry_exporter.rb +2 -1
  33. data/lib/datadog/appsec/monitor/gateway/watcher.rb +4 -4
  34. data/lib/datadog/appsec/remote.rb +25 -13
  35. data/lib/datadog/appsec/security_engine/result.rb +28 -9
  36. data/lib/datadog/appsec/security_engine/runner.rb +17 -7
  37. data/lib/datadog/appsec/security_event.rb +5 -7
  38. data/lib/datadog/core/configuration/components.rb +14 -6
  39. data/lib/datadog/core/configuration/stable_config.rb +10 -0
  40. data/lib/datadog/core/configuration/supported_configurations.rb +2 -0
  41. data/lib/datadog/core/configuration.rb +1 -1
  42. data/lib/datadog/core/ddsketch.rb +21 -0
  43. data/lib/datadog/core/environment/yjit.rb +2 -1
  44. data/lib/datadog/core/pin.rb +4 -8
  45. data/lib/datadog/core/process_discovery.rb +4 -2
  46. data/lib/datadog/core/remote/component.rb +4 -6
  47. data/lib/datadog/core/telemetry/component.rb +11 -0
  48. data/lib/datadog/core/telemetry/emitter.rb +6 -6
  49. data/lib/datadog/core/telemetry/event/app_endpoints_loaded.rb +30 -0
  50. data/lib/datadog/core/telemetry/event.rb +1 -0
  51. data/lib/datadog/core/transport/response.rb +4 -1
  52. data/lib/datadog/core/utils/network.rb +19 -0
  53. data/lib/datadog/di/boot.rb +1 -0
  54. data/lib/datadog/di/component.rb +14 -0
  55. data/lib/datadog/di/context.rb +70 -0
  56. data/lib/datadog/di/el/compiler.rb +164 -0
  57. data/lib/datadog/di/el/evaluator.rb +159 -0
  58. data/lib/datadog/di/el/expression.rb +42 -0
  59. data/lib/datadog/di/el.rb +5 -0
  60. data/lib/datadog/di/error.rb +25 -0
  61. data/lib/datadog/di/instrumenter.rb +101 -32
  62. data/lib/datadog/di/probe.rb +35 -15
  63. data/lib/datadog/di/probe_builder.rb +39 -1
  64. data/lib/datadog/di/probe_manager.rb +3 -2
  65. data/lib/datadog/di/probe_notification_builder.rb +50 -51
  66. data/lib/datadog/di/serializer.rb +151 -7
  67. data/lib/datadog/tracing/component.rb +6 -17
  68. data/lib/datadog/tracing/configuration/dynamic.rb +2 -2
  69. data/lib/datadog/tracing/configuration/settings.rb +3 -3
  70. data/lib/datadog/tracing/contrib/component.rb +2 -2
  71. data/lib/datadog/tracing/contrib/graphql/configuration/settings.rb +7 -0
  72. data/lib/datadog/tracing/contrib/graphql/ext.rb +1 -0
  73. data/lib/datadog/tracing/contrib/graphql/unified_trace.rb +53 -28
  74. data/lib/datadog/tracing/metadata/ext.rb +8 -0
  75. data/lib/datadog/version.rb +1 -1
  76. metadata +22 -9
  77. data/ext/libdatadog_api/macos_development.md +0 -26
@@ -2,51 +2,45 @@ AppSec WAF rules based on [appsec-event-rules](https://github.com/datadog/appsec
2
2
 
3
3
  ## How to update
4
4
 
5
- > [!WARNING]
6
- > This process is a temporary workaround to maintain compatibility with the existing code structure and will be changed.
5
+ In order to update rules, download `recommended.json` and `strict.json` of the desired version from [appsec-event-rules](https://github.com/datadog/appsec-event-rules) (example: [v1.13.3](https://github.com/DataDog/appsec-event-rules/tree/1.13.3/build))
7
6
 
8
- 1. Download `recommended.json` and `strict.json` of the desired version from [appsec-event-rules](https://github.com/datadog/appsec-event-rules) (example: [v1.13.3](https://github.com/DataDog/appsec-event-rules/tree/1.13.3/build))
9
- 2. Run the script below inside `waf_rules` folder to extract scanners and processors into separate files
7
+ You can store the following code as a `Rakefile` under `lib/datadog/appsec/assets/waf_rules`
10
8
 
11
- ```ruby
12
- require 'json'
9
+ ```ruby
10
+ def download(filename)
11
+ build_path = 'repos/DataDog/appsec-event-rules/contents/build'
13
12
 
14
- recommended_rules = JSON.parse(File.read(File.expand_path('recommended.json', __dir__)))
15
- strict_rules = JSON.parse(File.read(File.expand_path('strict.json', __dir__)))
13
+ system("gh api #{build_path}/#{filename} --jq '.content' | base64 -d > #{filename}")
14
+ end
16
15
 
17
- recommended_processors = recommended_rules.delete('processors')
18
- strict_processors = strict_rules.delete('processors')
16
+ task default: :update
19
17
 
20
- if recommended_processors.sort_by { |processor| processor['id'] } !=
21
- strict_processors.sort_by { |processor| processor['id'] }
22
- raise 'Processors are not the same, unable to extract them'
23
- end
18
+ task :verify_dependencies do
19
+ next if system('which gh 1>/dev/null')
24
20
 
25
- puts 'Extracting processors...'
26
- File.open(File.expand_path('processors.json', __dir__), 'wb') do |file|
27
- file.write(JSON.pretty_generate(recommended_processors))
28
- end
21
+ abort <<~MESSAGE
22
+ \033[0;33mNOTE: To successfully execute that task make sure you have
23
+ GitHub CLI installed and authenticated https://cli.github.com/\033[0m
24
+ MESSAGE
25
+ end
29
26
 
30
- recommended_scanners = recommended_rules.delete('scanners')
31
- strict_scanners = strict_rules.delete('scanners')
27
+ desc 'Update recommended.json and strict.json to the latest version'
28
+ task update: :verify_dependencies do
29
+ download('strict.json')
30
+ download('recommended.json')
32
31
 
33
- if recommended_scanners.sort_by { |processor| processor['id'] } !=
34
- strict_scanners.sort_by { |processor| processor['id'] }
35
- raise 'Scanners are not the same, unable to extract them'
36
- end
32
+ puts "\033[0;32mSuccess!\033[0m"
33
+ end
34
+ ```
37
35
 
38
- puts 'Extracting scanners...'
39
- File.open(File.expand_path('scanners.json', __dir__), 'wb') do |file|
40
- file.write(JSON.pretty_generate(recommended_scanners))
41
- end
36
+ And run the following command
42
37
 
43
- puts 'Updating rules...'
38
+ > [!IMPORTANT]
39
+ > To run that command you will need to install GitHub CLI tool and authenticate it
40
+ > See: https://cli.github.com/ (or ddtool)
44
41
 
45
- File.open(File.expand_path('recommended.json', __dir__), 'wb') do |file|
46
- file.write(JSON.pretty_generate(recommended_rules))
47
- end
48
42
 
49
- File.open(File.expand_path('strict.json', __dir__), 'wb') do |file|
50
- file.write(JSON.pretty_generate(strict_rules))
51
- end
52
- ```
43
+ ```console
44
+ $ bundle exec rake update
45
+ Success!
46
+ ```
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": "2.2",
3
3
  "metadata": {
4
- "rules_version": "1.14.2"
4
+ "rules_version": "1.15.1"
5
5
  },
6
6
  "rules": [
7
7
  {
@@ -2985,7 +2985,7 @@
2985
2985
  "address": "graphql.server.resolver"
2986
2986
  }
2987
2987
  ],
2988
- "regex": "\\b(?:(?:l(?:(?:utimes|chmod)(?:Sync)?|(?:stat|ink)Sync)|w(?:rite(?:(?:File|v)(?:Sync)?|Sync)|atchFile)|u(?:n(?:watchFile|linkSync)|times(?:Sync)?)|s(?:(?:ymlink|tat)Sync|pawn(?:File|Sync))|ex(?:ec(?:File(?:Sync)?|Sync)|istsSync)|a(?:ppendFile|ccess)(?:Sync)?|(?:Caveat|Inode)s|open(?:dir)?Sync|new\\s+Function|Availability|\\beval)\\s*\\(|m(?:ain(?:Module\\s*(?:\\W*\\s*(?:constructor|require)|\\[)|\\s*(?:\\W*\\s*(?:constructor|require)|\\[))|kd(?:temp(?:Sync)?|irSync)\\s*\\(|odule\\.exports\\s*=)|c(?:(?:(?:h(?:mod|own)|lose)Sync|reate(?:Write|Read)Stream|p(?:Sync)?)\\s*\\(|o(?:nstructor\\s*(?:\\W*\\s*_load|\\[)|pyFile(?:Sync)?\\s*\\())|f(?:(?:(?:s(?:(?:yncS)?|tatS)|datas(?:yncS)?)ync|ch(?:mod|own)(?:Sync)?)\\s*\\(|u(?:nction\\s*\\(\\s*\\)\\s*{|times(?:Sync)?\\s*\\())|r(?:e(?:(?:ad(?:(?:File|link|dir)?Sync|v(?:Sync)?)|nameSync)\\s*\\(|quire\\s*(?:\\W*\\s*main|\\[))|m(?:Sync)?\\s*\\()|process\\s*(?:\\W*\\s*(?:mainModule|binding)|\\[)|t(?:his\\.constructor|runcateSync\\s*\\()|_(?:\\$\\$ND_FUNC\\$\\$_|_js_function)|global\\s*(?:\\W*\\s*process|\\[)|String\\s*\\.\\s*fromCharCode|binding\\s*\\[)",
2988
+ "regex": "\\b(?:(?:l(?:(?:utimes|chmod)(?:Sync)?|(?:stat|ink)Sync)|w(?:rite(?:(?:File|v)(?:Sync)?|Sync)|atchFile)|u(?:n(?:watchFile|linkSync)|times(?:Sync)?)|s(?:(?:ymlink|tat)Sync|pawn(?:File|Sync))|ex(?:ec(?:File(?:Sync)?|Sync)|istsSync)|a(?:ppendFile|ccess)(?:Sync)?|(?:Caveat|Inode)s|open(?:dir)?Sync|new\\s+Function|Availability|\\beval)\\s*\\(|m(?:ain(?:Module\\s*(?:\\W*\\s*(?:constructor|require)|\\[)|\\s*(?:\\W*\\s*(?:constructor|require)|\\[))|kd(?:temp(?:Sync)?|irSync)\\s*\\(|odule\\.exports\\s*=)|c(?:(?:(?:h(?:mod|own)|lose)Sync|reate(?:Write|Read)Stream|p(?:Sync)?)\\s*\\(|o(?:nstructor\\s*(?:\\W*\\s*_load|\\[)|pyFile(?:Sync)?\\s*\\())|f(?:(?:(?:s(?:(?:yncS)?|tatS)|datas(?:yncS)?)ync|ch(?:mod|own)(?:Sync)?)\\s*\\(|u(?:nction\\s*\\(\\s*\\)\\s*{|times(?:Sync)?\\s*\\())|r(?:e(?:(?:ad(?:(?:File|link|dir)?Sync|v(?:Sync)?)|nameSync)\\s*\\(|quire\\s*(?:\\W*\\s*main\\b|\\[))|m(?:Sync)?\\s*\\()|process\\s*(?:\\W*\\s*(?:mainModule|binding)|\\[)|t(?:his\\.constructor|runcateSync\\s*\\()|_(?:\\$\\$ND_FUNC\\$\\$_|_js_function)|global\\s*(?:\\W*\\s*process|\\[)|String\\s*\\.\\s*fromCharCode|binding\\s*\\[)",
2989
2989
  "options": {
2990
2990
  "case_sensitive": true,
2991
2991
  "min_length": 3
@@ -5539,6 +5539,7 @@
5539
5539
  "confidence": "0",
5540
5540
  "module": "waf"
5541
5541
  },
5542
+ "max_version": "1.24.9",
5542
5543
  "conditions": [
5543
5544
  {
5544
5545
  "parameters": {
@@ -5656,6 +5657,52 @@
5656
5657
  ],
5657
5658
  "transformers": []
5658
5659
  },
5660
+ {
5661
+ "id": "dog-932-110",
5662
+ "name": "Python: Subprocess-based command injection",
5663
+ "tags": {
5664
+ "type": "command_injection",
5665
+ "category": "attack_attempt",
5666
+ "confidence": "0",
5667
+ "module": "waf"
5668
+ },
5669
+ "conditions": [
5670
+ {
5671
+ "parameters": {
5672
+ "inputs": [
5673
+ {
5674
+ "address": "server.request.query"
5675
+ },
5676
+ {
5677
+ "address": "server.request.body"
5678
+ },
5679
+ {
5680
+ "address": "server.request.path_params"
5681
+ },
5682
+ {
5683
+ "address": "server.request.headers.no_cookies"
5684
+ },
5685
+ {
5686
+ "address": "grpc.server.request.message"
5687
+ },
5688
+ {
5689
+ "address": "graphql.server.all_resolvers"
5690
+ },
5691
+ {
5692
+ "address": "graphql.server.resolver"
5693
+ }
5694
+ ],
5695
+ "regex": "(?s)\\bsubprocess\\b.*\\b(?:check_output|run|Popen|call|check_call)\\b",
5696
+ "options": {
5697
+ "case_sensitive": true,
5698
+ "min_length": 14
5699
+ }
5700
+ },
5701
+ "operator": "match_regex"
5702
+ }
5703
+ ],
5704
+ "transformers": []
5705
+ },
5659
5706
  {
5660
5707
  "id": "dog-934-001",
5661
5708
  "name": "XXE - XML file loads external entity",
@@ -6625,7 +6672,10 @@
6625
6672
  {
6626
6673
  "address": "graphql.server.resolver"
6627
6674
  }
6628
- ]
6675
+ ],
6676
+ "options": {
6677
+ "path-inspection": true
6678
+ }
6629
6679
  },
6630
6680
  "operator": "ssrf_detector"
6631
6681
  }
@@ -8870,6 +8920,271 @@
8870
8920
  "transformers": []
8871
8921
  }
8872
8922
  ],
8923
+ "rules_compat": [
8924
+ {
8925
+ "id": "api-001-100",
8926
+ "name": "JWT: No expiry is present",
8927
+ "tags": {
8928
+ "type": "jwt",
8929
+ "category": "api_security",
8930
+ "confidence": "0",
8931
+ "module": "business-logic"
8932
+ },
8933
+ "min_version": "1.25.0",
8934
+ "conditions": [
8935
+ {
8936
+ "parameters": {
8937
+ "inputs": [
8938
+ {
8939
+ "address": "server.request.jwt",
8940
+ "key_path": [
8941
+ "payload",
8942
+ "exp"
8943
+ ]
8944
+ }
8945
+ ]
8946
+ },
8947
+ "operator": "!exists"
8948
+ }
8949
+ ],
8950
+ "transformers": [],
8951
+ "output": {
8952
+ "event": false,
8953
+ "keep": false,
8954
+ "attributes": {
8955
+ "_dd.appsec.api.jwt.no_expiry": {
8956
+ "value": 1
8957
+ }
8958
+ }
8959
+ }
8960
+ },
8961
+ {
8962
+ "id": "api-001-110",
8963
+ "name": "JWT: Collect algorithm used",
8964
+ "tags": {
8965
+ "type": "jwt",
8966
+ "category": "api_security",
8967
+ "confidence": "0",
8968
+ "module": "business-logic"
8969
+ },
8970
+ "min_version": "1.25.0",
8971
+ "conditions": [
8972
+ {
8973
+ "parameters": {
8974
+ "inputs": [
8975
+ {
8976
+ "address": "server.request.jwt",
8977
+ "key_path": [
8978
+ "header",
8979
+ "alg"
8980
+ ]
8981
+ }
8982
+ ]
8983
+ },
8984
+ "operator": "exists"
8985
+ }
8986
+ ],
8987
+ "transformers": [],
8988
+ "output": {
8989
+ "event": false,
8990
+ "keep": false,
8991
+ "attributes": {
8992
+ "_dd.appsec.api.jwt_alg": {
8993
+ "address": "server.request.jwt",
8994
+ "key_path": [
8995
+ "header",
8996
+ "alg"
8997
+ ]
8998
+ }
8999
+ }
9000
+ }
9001
+ },
9002
+ {
9003
+ "id": "api-001-120",
9004
+ "name": "JWT: No audience is specified",
9005
+ "tags": {
9006
+ "type": "jwt",
9007
+ "category": "api_security",
9008
+ "confidence": "0",
9009
+ "module": "business-logic"
9010
+ },
9011
+ "min_version": "1.25.0",
9012
+ "conditions": [
9013
+ {
9014
+ "parameters": {
9015
+ "inputs": [
9016
+ {
9017
+ "address": "server.request.jwt",
9018
+ "key_path": [
9019
+ "payload",
9020
+ "aud"
9021
+ ]
9022
+ }
9023
+ ]
9024
+ },
9025
+ "operator": "!exists"
9026
+ }
9027
+ ],
9028
+ "transformers": [],
9029
+ "output": {
9030
+ "event": false,
9031
+ "keep": false,
9032
+ "attributes": {
9033
+ "_dd.appsec.api.jwt.no_audience": {
9034
+ "value": 1
9035
+ }
9036
+ }
9037
+ }
9038
+ },
9039
+ {
9040
+ "id": "api-001-130",
9041
+ "name": "JWT: None algorithm used",
9042
+ "tags": {
9043
+ "type": "jwt",
9044
+ "category": "api_security",
9045
+ "confidence": "0",
9046
+ "module": "business-logic"
9047
+ },
9048
+ "min_version": "1.25.0",
9049
+ "conditions": [
9050
+ {
9051
+ "parameters": {
9052
+ "inputs": [
9053
+ {
9054
+ "address": "server.request.jwt",
9055
+ "key_path": [
9056
+ "header",
9057
+ "alg"
9058
+ ]
9059
+ }
9060
+ ],
9061
+ "list": [
9062
+ "none",
9063
+ "nonE",
9064
+ "noNe",
9065
+ "noNE",
9066
+ "nOne",
9067
+ "nOnE",
9068
+ "nONe",
9069
+ "nONE",
9070
+ "None",
9071
+ "NonE",
9072
+ "NoNe",
9073
+ "NoNE",
9074
+ "NOne",
9075
+ "NOnE",
9076
+ "NONe",
9077
+ "NONE"
9078
+ ]
9079
+ },
9080
+ "operator": "exact_match"
9081
+ }
9082
+ ],
9083
+ "transformers": [],
9084
+ "output": {
9085
+ "event": false,
9086
+ "keep": true,
9087
+ "attributes": {
9088
+ "_dd.appsec.api.jwt.none_alg": {
9089
+ "value": 1
9090
+ }
9091
+ }
9092
+ }
9093
+ },
9094
+ {
9095
+ "id": "ua0-600-551",
9096
+ "name": "Datadog test scanner - scalar trace-tagging version: user-agent",
9097
+ "tags": {
9098
+ "type": "security_scanner",
9099
+ "category": "attack_attempt",
9100
+ "cwe": "200",
9101
+ "capec": "1000/118/169",
9102
+ "tool_name": "Datadog Canary Test",
9103
+ "confidence": "1",
9104
+ "module": "waf"
9105
+ },
9106
+ "min_version": "1.25.0",
9107
+ "conditions": [
9108
+ {
9109
+ "parameters": {
9110
+ "inputs": [
9111
+ {
9112
+ "address": "server.request.headers.no_cookies",
9113
+ "key_path": [
9114
+ "user-agent"
9115
+ ]
9116
+ },
9117
+ {
9118
+ "address": "grpc.server.request.metadata",
9119
+ "key_path": [
9120
+ "dd-canary"
9121
+ ]
9122
+ }
9123
+ ],
9124
+ "regex": "^dd-test-scanner-tag-scalar(?:$|/|\\s)"
9125
+ },
9126
+ "operator": "match_regex"
9127
+ }
9128
+ ],
9129
+ "transformers": [],
9130
+ "output": {
9131
+ "event": false,
9132
+ "attributes": {
9133
+ "_dd.appsec.test.scanner.scalar": {
9134
+ "value": 1
9135
+ }
9136
+ }
9137
+ }
9138
+ },
9139
+ {
9140
+ "id": "ua0-600-552",
9141
+ "name": "Datadog test scanner - reference trace-tagging version: user-agent",
9142
+ "tags": {
9143
+ "type": "security_scanner",
9144
+ "category": "attack_attempt",
9145
+ "cwe": "200",
9146
+ "capec": "1000/118/169",
9147
+ "tool_name": "Datadog Canary Test",
9148
+ "confidence": "1",
9149
+ "module": "waf"
9150
+ },
9151
+ "min_version": "1.25.0",
9152
+ "conditions": [
9153
+ {
9154
+ "parameters": {
9155
+ "inputs": [
9156
+ {
9157
+ "address": "server.request.headers.no_cookies",
9158
+ "key_path": [
9159
+ "user-agent"
9160
+ ]
9161
+ },
9162
+ {
9163
+ "address": "grpc.server.request.metadata",
9164
+ "key_path": [
9165
+ "dd-canary"
9166
+ ]
9167
+ }
9168
+ ],
9169
+ "regex": "^dd-test-scanner-tag-ref(?:$|/|\\s)"
9170
+ },
9171
+ "operator": "match_regex"
9172
+ }
9173
+ ],
9174
+ "transformers": [],
9175
+ "output": {
9176
+ "event": false,
9177
+ "attributes": {
9178
+ "_dd.appsec.test.scanner.reference": {
9179
+ "address": "server.request.headers.no_cookies",
9180
+ "key_path": [
9181
+ "user-agent"
9182
+ ]
9183
+ }
9184
+ }
9185
+ }
9186
+ }
9187
+ ],
8873
9188
  "processors": [
8874
9189
  {
8875
9190
  "id": "http-endpoint-fingerprint",
@@ -9074,6 +9389,28 @@
9074
9389
  "evaluate": true,
9075
9390
  "output": true
9076
9391
  },
9392
+ {
9393
+ "id": "decode-auth-jwt",
9394
+ "generator": "jwt_decode",
9395
+ "min_version": "1.25.0",
9396
+ "parameters": {
9397
+ "mappings": [
9398
+ {
9399
+ "inputs": [
9400
+ {
9401
+ "address": "server.request.headers.no_cookies",
9402
+ "key_path": [
9403
+ "authorization"
9404
+ ]
9405
+ }
9406
+ ],
9407
+ "output": "server.request.jwt"
9408
+ }
9409
+ ]
9410
+ },
9411
+ "evaluate": true,
9412
+ "output": false
9413
+ },
9077
9414
  {
9078
9415
  "id": "http-network-fingerprint",
9079
9416
  "generator": "http_network_fingerprint",
@@ -9918,6 +10255,24 @@
9918
10255
  "category": "payment"
9919
10256
  }
9920
10257
  },
10258
+ {
10259
+ "id": "c542c147-3883-43d6-a067-178e4a7bd65d",
10260
+ "name": "Password",
10261
+ "key": {
10262
+ "operator": "match_regex",
10263
+ "parameters": {
10264
+ "regex": "\\bpass(?:[_-]?word|wd)?\\b|\\bpwd\\b",
10265
+ "options": {
10266
+ "case_sensitive": false,
10267
+ "min_length": 3
10268
+ }
10269
+ }
10270
+ },
10271
+ "tags": {
10272
+ "type": "password",
10273
+ "category": "credentials"
10274
+ }
10275
+ },
9921
10276
  {
9922
10277
  "id": "18b608bd7a764bff5b2344c0",
9923
10278
  "name": "Phone number",
@@ -10146,4 +10501,4 @@
10146
10501
  }
10147
10502
  }
10148
10503
  ]
10149
- }
10504
+ }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": "2.2",
3
3
  "metadata": {
4
- "rules_version": "1.14.2"
4
+ "rules_version": "1.15.1"
5
5
  },
6
6
  "rules": [
7
7
  {
@@ -1746,6 +1746,7 @@
1746
1746
  "transformers": []
1747
1747
  }
1748
1748
  ],
1749
+ "rules_compat": [],
1749
1750
  "processors": [
1750
1751
  {
1751
1752
  "id": "http-endpoint-fingerprint",
@@ -1950,6 +1951,28 @@
1950
1951
  "evaluate": true,
1951
1952
  "output": true
1952
1953
  },
1954
+ {
1955
+ "id": "decode-auth-jwt",
1956
+ "generator": "jwt_decode",
1957
+ "min_version": "1.25.0",
1958
+ "parameters": {
1959
+ "mappings": [
1960
+ {
1961
+ "inputs": [
1962
+ {
1963
+ "address": "server.request.headers.no_cookies",
1964
+ "key_path": [
1965
+ "authorization"
1966
+ ]
1967
+ }
1968
+ ],
1969
+ "output": "server.request.jwt"
1970
+ }
1971
+ ]
1972
+ },
1973
+ "evaluate": true,
1974
+ "output": false
1975
+ },
1953
1976
  {
1954
1977
  "id": "http-network-fingerprint",
1955
1978
  "generator": "http_network_fingerprint",
@@ -2794,6 +2817,24 @@
2794
2817
  "category": "payment"
2795
2818
  }
2796
2819
  },
2820
+ {
2821
+ "id": "c542c147-3883-43d6-a067-178e4a7bd65d",
2822
+ "name": "Password",
2823
+ "key": {
2824
+ "operator": "match_regex",
2825
+ "parameters": {
2826
+ "regex": "\\bpass(?:[_-]?word|wd)?\\b|\\bpwd\\b",
2827
+ "options": {
2828
+ "case_sensitive": false,
2829
+ "min_length": 3
2830
+ }
2831
+ }
2832
+ },
2833
+ "tags": {
2834
+ "type": "password",
2835
+ "category": "credentials"
2836
+ }
2837
+ },
2797
2838
  {
2798
2839
  "id": "18b608bd7a764bff5b2344c0",
2799
2840
  "name": "Phone number",
@@ -3022,4 +3063,4 @@
3022
3063
  }
3023
3064
  }
3024
3065
  ]
3025
- }
3066
+ }
@@ -8,7 +8,7 @@ require_relative '../core/utils/base64'
8
8
 
9
9
  module Datadog
10
10
  module AppSec
11
- # Converts derivative schema payloads into JSON and compresses them into a
11
+ # Converts complex schema payloads into JSON and compresses them into a
12
12
  # base64 encoded string if the payload is worth compressing.
13
13
  #
14
14
  # See: https://github.com/DataDog/dd-trace-rb/pull/3177#issuecomment-1747221082
@@ -352,6 +352,15 @@ module Datadog
352
352
  o.default true
353
353
  end
354
354
 
355
+ settings :endpoint_collection do
356
+ # Enables reporting of application routes at application start via telemetry
357
+ option :enabled do |o|
358
+ o.type :bool, nilable: true
359
+ o.env 'DD_API_SECURITY_ENDPOINT_COLLECTION_ENABLED'
360
+ o.default true
361
+ end
362
+ end
363
+
355
364
  # NOTE: Unfortunately, we have to go with Float due to other libs
356
365
  # setup, even tho we don't plan to support sub-second delays.
357
366
  #
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative '../../event'
4
+ require_relative '../../trace_keeper'
4
5
  require_relative '../../security_event'
5
6
 
6
7
  module Datadog
@@ -31,7 +32,8 @@ module Datadog
31
32
  result = context.run_rasp(Ext::RASP_SQLI, {}, ephemeral_data, waf_timeout)
32
33
 
33
34
  if result.match?
34
- AppSec::Event.tag_and_keep!(context, result)
35
+ AppSec::Event.tag(context, result)
36
+ TraceKeeper.keep!(context.trace) if result.keep?
35
37
 
36
38
  context.events.push(
37
39
  AppSec::SecurityEvent.new(result, trace: context.trace, span: context.span)
@@ -3,6 +3,7 @@
3
3
  require 'excon'
4
4
 
5
5
  require_relative '../../event'
6
+ require_relative '../../trace_keeper'
6
7
  require_relative '../../security_event'
7
8
 
8
9
  module Datadog
@@ -22,7 +23,8 @@ module Datadog
22
23
  result = context.run_rasp(Ext::RASP_SSRF, {}, ephemeral_data, Datadog.configuration.appsec.waf_timeout)
23
24
 
24
25
  if result.match?
25
- AppSec::Event.tag_and_keep!(context, result)
26
+ AppSec::Event.tag(context, result)
27
+ TraceKeeper.keep!(context.trace) if result.keep?
26
28
 
27
29
  context.events.push(
28
30
  AppSec::SecurityEvent.new(result, trace: context.trace, span: context.span)
@@ -38,4 +40,3 @@ module Datadog
38
40
  end
39
41
  end
40
42
  end
41
- # rubocop:enable Naming/FileName
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative '../../event'
4
+ require_relative '../../trace_keeper'
4
5
  require_relative '../../security_event'
5
6
 
6
7
  module Datadog
@@ -21,7 +22,8 @@ module Datadog
21
22
  result = context.run_rasp(Ext::RASP_SSRF, {}, ephemeral_data, Datadog.configuration.appsec.waf_timeout)
22
23
 
23
24
  if result.match?
24
- AppSec::Event.tag_and_keep!(context, result)
25
+ AppSec::Event.tag(context, result)
26
+ TraceKeeper.keep!(context.trace) if result.keep?
25
27
 
26
28
  context.events.push(
27
29
  AppSec::SecurityEvent.new(result, trace: context.trace, span: context.span)
@@ -3,6 +3,7 @@
3
3
  require 'json'
4
4
 
5
5
  require_relative '../../../event'
6
+ require_relative '../../../trace_keeper'
6
7
  require_relative '../../../security_event'
7
8
  require_relative '../../../instrumentation/gateway'
8
9
 
@@ -32,7 +33,8 @@ module Datadog
32
33
  result = context.run_waf(persistent_data, {}, Datadog.configuration.appsec.waf_timeout)
33
34
 
34
35
  if result.match?
35
- AppSec::Event.tag_and_keep!(context, result)
36
+ AppSec::Event.tag(context, result)
37
+ TraceKeeper.keep!(context.trace) if result.keep?
36
38
 
37
39
  context.events.push(
38
40
  AppSec::SecurityEvent.new(result, trace: context.trace, span: context.span)