`EventScrubber` doesn't scrub a request body that's a top level JSON array

未关闭 适合新手
#7,543 1 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

还没有人认领这个 Issue。

评估

难度
2/5
预计耗时
1-3 小时
新手友好度
78/100
Issue 类型
缺陷
描述清晰度
描述清楚
活跃度
活跃
技术栈
flask, python
领域
security

调研方向

使用提供的 repro.py 重现该问题,然后检查 EventScrubber.scrub_request、scrub_dict 和 scrub_list,以跟踪请求数据的处理方式。使用现有的 scrubber 测试,或为顶层数组添加覆盖;当数组 body 中嵌套的 password 或 api_key 值能够像对象 body 中一样被过滤时,即表示完成。

由索引模型根据 Issue 内容生成。

描述

Waiting for: Product Owner
How do you use Sentry?

Sentry Saas (sentry.io)

Version

2.69.2 (also on master at 494ecb3)

Steps to Reproduce

When a request body parses to a top level JSON array, nothing in it gets scrubbed. The same secrets in an object body are filtered normally. No event_scrubber argument, no _experiments data collection config, default max_request_body_size. The integration and the transport in the snippet are only there to catch the event.

A top level array is the usual shape for a bulk endpoint, something like POST /api/v1/users/bulk with a list of records. If those records carry a password or an api_key, they leave the process in the clear. A team that spot checks a single object endpoint sees scrubbing work fine, so there's nothing to tip them off.

Python 3.13.15, Flask 3.1.3, sentry-sdk 2.69.2. Save this as repro.py and run it.

import json
import logging

import sentry_sdk
from flask import Flask
from sentry_sdk.integrations.flask import FlaskIntegration

events = []


class Capture(sentry_sdk.transport.Transport):
    def capture_envelope(self, envelope):
        for item in envelope.items:
            if item.headers.get("type") == "event":
                events.append(item.payload.json)


sentry_sdk.init(
    dsn="https://public@example.com/1",
    integrations=[FlaskIntegration()],
    transport=Capture(),
)

app = Flask(__name__)
app.logger.disabled = True
logging.getLogger("werkzeug").disabled = True


@app.route("/bulk", methods=["POST"])
def bulk():
    raise ValueError("boom")


@app.route("/single", methods=["POST"])
def single():
    raise ValueError("boom")


client = app.test_client()
client.post("/bulk", json=[{"user": "a", "password": "hunter2"}])
client.post("/single", json={"user": "a", "password": "hunter2"})
sentry_sdk.get_client().close()

print("array body :", json.dumps(events[0]["request"]["data"]))
print("object body:", json.dumps(events[1]["request"]["data"]))
Expected Result

The array body should come out filtered the same way the object body does:

array body : [{"password": "[Filtered]", "user": "a"}]
object body: {"password": "[Filtered]", "user": "a"}
Actual Result
array body : [{"password": "hunter2", "user": "a"}]
object body: {"password": "[Filtered]", "user": "a"}

EventScrubber.scrub_request calls scrub_dict on event["request"]["data"], and scrub_dict returns immediately when what it's given isn't a dict, so a list body stops scrubbing before it starts. The class already ships scrub_list, whose docstring says it walks a list and any nested lists and calls scrub_dict on every dictionary it finds, but it's never called on the request body.

This is separate from #7542, which is about how denylist keys are matched. Here the keys never get looked at at all. I have a fix and tests ready if you want a PR.

主要语言
Python
星标
2.2k
派生
672
平均合并
1 天 13 分钟
30 天内合并 PR
212

贡献指南

打开贡献指南

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

getsentry/sentry-python 的其他 Issue

查看 getsentry/sentry-python 的全部 Issue

相似的 Issue

更多 Python Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。