-
Notifications
You must be signed in to change notification settings - Fork 1.7k
feat(RiskAcc-Eng): Clean RiskAcc-Eng mapping + Allow correct handling by API #12361
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Conversation
I think the initial idea was that a Risk Acceptance could apply to more than just one engagement. For example accept the risk of a CVE that occurs in multiple branches. I think via the UI you cannot actually do this, but it might be possible via the API? |
API would not be broken; there is a checker correctly (see below). In fact, API needs to be fixed - you can create RiskAcc (via
I'm not strictly to one or another option. Both might make sense. It is the reason why I didn't continue with the implementation, but raised the question. Regarding breaking the current setup - I do not think so because we would just extend current abilities (but please correct me if I'm wrong). It might not be true about future use cases. But it is the reason why I'm asking about original intentions. |
f462a9d
to
96a904f
Compare
This pull request introduces potential risks in database migration and model relationships, including null reference scenarios, incomplete migration logic, unintended data deletion through CASCADE strategy, and changes to data relationships that could impact existing data tracking between Engagement and Risk_Acceptance models. 💭 Unconfirmed Findings (4)
All finding details can be found in the DryRun Security Dashboard. |
Hi @kiblik, thank you for pausing on this feature before continuing any further. Risk Exceptions are one of those features that is used a little differently by everyone. As Val pointed out, we don't want to break any current use cases, or point ourselves into a corner for future use cases. Minimizing changes to the risk exception object would be the best move we could make at this time |
Thank you @Maffooch. I will prepare the implementation, which will:
|
3e2f9df
to
9f3cf6d
Compare
ba53851
to
e4d0be7
Compare
This pull request has conflicts, please resolve those before we can evaluate the pull request. |
e4d0be7
to
480165b
Compare
Conflicts have been resolved. A maintainer will review the pull request shortly. |
8755e4f
to
68a6482
Compare
1730b85
to
1b2358d
Compare
1b2358d
to
312c07c
Compare
f83fd48
to
4bf8bc4
Compare
4bf8bc4
to
ec21f6a
Compare
6a4097f
to
b61eca2
Compare
b61eca2
to
12930cb
Compare
Hi all, I am the author of the bug that triggered this discussion. @valentijnscholten - as for your question "it might be possible via the API?" I tried that, but I got an error that is not possible to have findings from different engagements under the same risk acceptance, so there is a validation somewhere. As for the general use case for Risk Acceptances. It is quite common for us to accept the risk for a certain CVE across the whole business. In our view, it should be possible to have a single Risk Acceptance comprising many findings across many engagements. I would like to think this is a very common requirement for many companies Because it is not possible to have a single Risk Acceptance across engagements, we had to implement workarounds. We created a script that creates one Risk Acceptance per finding. It could happen that we create more than 1k Risk Acceptances for a single CVE, this is not ideal, we may clog the DB at some point. |
I hope you are not the author of the bug, but only the author of the bug report 😄 You are writing at the best time. I almost finished this PR (only one validation statement and a fix of unittests are missing). I wrote it in a way that reflects current behaviour (allows mapping RiskAcc only to engagements), but correctly handled in case of API processing. On the other hand, I agree that if there is no specific use case (and I do not know it), I suppose it might be a much better idea to move RiskAcc from the Engagement level to the Product level. Cross-product level would not be the best because I'm not sure how we would handle permissions there (e.g., Can I see all RAs? Because if I want to add my findings to some pre-created RA, I need to be able to see it). @Maffooch, @valentijnscholten, @mtesauro, can I ask you for reconsideration? Change from the Engagement level to the Product level would not break any correct implementation; it would just open the door for a more flexible definition/handling. |
We also have this use case:
E.g. you track multiple versions of a product in different engagement (within the same product or multiple). Then a new CVE gets reported. You investigate and see that it has no effect to you. Therefor We would like to accept it for all installed Versions (so multiple engagements) as single Risk Acceptance since it has been evaluated together. Depending on the Application/System, this can affect many CVE (e.g. because it is not exposed). |
This pull request has conflicts, please resolve those before we can evaluate the pull request. |
@Maffooch, @valentijnscholten, @mtesauro, can I know your opinion? |
This pull request introduces three potential security vulnerabilities: an authorization bypass risk in risk acceptance functions, an information disclosure issue through API filtering of 'notes' fields, and an information leakage vulnerability in validation error handling that exposes internal finding IDs.
Authorization Bypass via Sole Decorator Reliance in
|
Vulnerability | Authorization Bypass via Sole Decorator Reliance |
---|---|
Description | The expire_risk_acceptance , reinstate_risk_acceptance , and delete_risk_acceptance functions rely exclusively on the @user_is_authorized decorator for access control. There are no additional in-function authorization checks. This single point of failure means that if the decorator is bypassed, misconfigured, or contains a vulnerability, an unauthorized user could potentially perform these sensitive operations. |
django-DefectDojo/dojo/engagement/views.py
Lines 1433 to 1464 in 12930cb
}) | |
@user_is_authorized(Risk_Acceptance, Permissions.Risk_Acceptance, "raid") | |
def expire_risk_acceptance(request, raid): | |
risk_acceptance = get_object_or_404(prefetch_for_expiration(Risk_Acceptance.objects.all()), pk=raid) | |
ra_helper.expire_now(risk_acceptance) | |
return redirect_to_return_url_or_else(request, reverse("view_risk_acceptance", args=(raid, ))) | |
@user_is_authorized(Risk_Acceptance, Permissions.Risk_Acceptance, "raid") | |
def reinstate_risk_acceptance(request, raid): | |
risk_acceptance = get_object_or_404(prefetch_for_expiration(Risk_Acceptance.objects.all()), pk=raid) | |
eng = risk_acceptance.engagement | |
if not eng.product.enable_full_risk_acceptance: | |
raise PermissionDenied | |
ra_helper.reinstate(risk_acceptance, risk_acceptance.expiration_date) | |
return redirect_to_return_url_or_else(request, reverse("view_risk_acceptance", args=(raid, ))) | |
@user_is_authorized(Risk_Acceptance, Permissions.Risk_Acceptance, "raid") | |
def delete_risk_acceptance(request, raid): | |
risk_acceptance = get_object_or_404(Risk_Acceptance, pk=raid) | |
eng = risk_acceptance.engagement | |
ra_helper.delete(eng, risk_acceptance) | |
Information Disclosure via 'notes' field exposure in dojo/filters.py
Vulnerability | Information Disclosure via 'notes' field exposure |
---|---|
Description | The patch adds the 'notes' field to the RiskAcceptanceFilter , making it filterable via the API. This, combined with the API view prefetching the 'notes' field, creates a potential for information disclosure. Even with object-level permissions, a user could use the filter to infer sensitive information from notes of risk acceptances they are not authorized to directly view, by observing filter results (blind information disclosure). |
django-DefectDojo/dojo/filters.py
Lines 2800 to 2806 in 12930cb
"name", "accepted_findings", "recommendation", "recommendation_details", | |
"decision", "decision_details", "accepted_by", "owner", "expiration_date", | |
"expiration_date_warned", "expiration_date_handled", "reactivate_expired", | |
"restart_sla_expired", "notes", "engagement", | |
] | |
Information Disclosure via ValidationError in dojo/models.py
Vulnerability | Information Disclosure via ValidationError |
---|---|
Description | The Risk_Acceptance.clean() method and the validate_findings_engagement helper function (called by RiskAcceptanceSerializer ) raise a ValidationError that includes the internal database IDs of 'Finding' objects that do not belong to the specified engagement. When this validation error is triggered via the API, these internal IDs are exposed in the API response. This allows an attacker to confirm the existence and internal IDs of findings they may not otherwise be authorized to view, leading to information disclosure. |
django-DefectDojo/dojo/models.py
Lines 3685 to 3700 in 12930cb
def __str__(self): | |
return str(self.name) | |
def clean(self): | |
super().clean() | |
if self.pk: | |
# Get all findings that do NOT belong to this engagement | |
problematic_findings = self.accepted_findings.exclude(test__engagement=self.engagement) | |
if problematic_findings.exists(): | |
problematic_ids = list(problematic_findings.values_list("id", flat=True)) | |
msg = f"Findings with IDs {problematic_ids} do not belong to engagement {self.engagement_id}." | |
raise ValidationError(msg) | |
def filename(self): | |
# logger.debug('path: "%s"', self.path) | |
if not self.path: |
All finding details can be found in the DryRun Security Dashboard.
This PR is trying to fix "not the best" implementation of mapping between Engagements and RiskAcc.
Until now, it was set as
ManyToManyField
inEngagements
, and fromRiskAcc
, it was just using the first possible match. This implementation is eventually a one-to-many relation, which should be solved viaForeignKey
inRiskAcc
.