Skip to content

Commit 91d8971

Browse files
authored
Merge pull request #47 from GitHubSecurityLab/filter_severity
add taskflow to filter severity
2 parents 878faef + ccfe027 commit 91d8971

3 files changed

Lines changed: 119 additions & 1 deletion

File tree

src/seclab_taskflows/mcp_servers/repo_context.py

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from seclab_taskflow_agent.path_utils import mcp_data_dir, log_file_name
1616

1717
from .repo_context_models import Application, EntryPoint, UserAction, WebEntryPoint, ApplicationIssue, AuditResult, Base
18+
from .repo_context_models import LowSeverityAuditResult
1819
from .utils import process_repo
1920

2021
logging.basicConfig(
@@ -26,7 +27,6 @@
2627

2728
MEMORY = mcp_data_dir("seclab-taskflows", "repo_context", "REPO_CONTEXT_DIR")
2829

29-
3030
def app_to_dict(result):
3131
return {
3232
"app_id": result.id,
@@ -107,6 +107,7 @@ def __init__(self, memcache_state_dir: str):
107107
WebEntryPoint.__table__,
108108
ApplicationIssue.__table__,
109109
AuditResult.__table__,
110+
LowSeverityAuditResult.__table__,
110111
],
111112
)
112113

@@ -239,6 +240,22 @@ def store_new_user_action(self, repo, app_id, file, line, notes, update=False):
239240
session.add(new_user_action)
240241
session.commit()
241242
return f"Updated or added user action for {file} and {line} in {repo}."
243+
244+
def store_low_severity_reason(self, repo, component_id, result_id, reason):
245+
with Session(self.engine) as session:
246+
existing = session.query(LowSeverityAuditResult).filter_by(repo=repo, result_id=result_id).first()
247+
if existing:
248+
existing.reason += reason
249+
else:
250+
new_low_severity_result = LowSeverityAuditResult(
251+
repo=repo,
252+
component_id=component_id,
253+
result_id=result_id,
254+
reason=reason,
255+
)
256+
session.add(new_low_severity_result)
257+
session.commit()
258+
return f"Updated or added low severity result for {repo} and result id {result_id}"
242259

243260
def get_app(self, repo, location):
244261
with Session(self.engine) as session:
@@ -294,6 +311,7 @@ def get_app_audit_results(self, repo, component_id, has_non_security_error, has_
294311
"repo": app.repo,
295312
"issue_type": issue.issue_type,
296313
"issue_id": issue.issue_id,
314+
"result_id" : issue.id,
297315
"notes": issue.notes,
298316
"has_vulnerability": issue.has_vulnerability,
299317
"has_non_security_error": issue.has_non_security_error,
@@ -389,6 +407,7 @@ def clear_repo(self, repo):
389407
session.query(ApplicationIssue).filter_by(repo=repo).delete()
390408
session.query(WebEntryPoint).filter_by(repo=repo).delete()
391409
session.query(AuditResult).filter_by(repo=repo).delete()
410+
session.query(LowSeverityAuditResult).filter_by(repo=repo).delete()
392411
session.commit()
393412
return f"Cleared results for repo {repo}"
394413

@@ -782,6 +801,19 @@ def get_potential_audit_results_for_repo(
782801
backend.get_app_audit_results(repo, component_id=None, has_non_security_error=True, has_vulnerability=None)
783802
)
784803

804+
@mcp.tool()
805+
def store_low_severity_reason(
806+
owner: str = Field(description="The owner of the GitHub repository"),
807+
repo: str = Field(description="The name of the GitHub repository"),
808+
component_id: int = Field(description="The ID of the component"),
809+
result_id: int = Field(description="The ID of the audit result"),
810+
reason: str = Field(description="The reason why this issue is not considered high severity"),
811+
):
812+
"""
813+
Store the reason for auditing an issue as low severity.
814+
"""
815+
repo = process_repo(owner, repo)
816+
return backend.store_low_severity_reason(repo, component_id, result_id, reason)
785817

786818
@mcp.tool()
787819
def clear_repo(

src/seclab_taskflows/mcp_servers/repo_context_models.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,19 @@ def __repr__(self):
6060
f"component_id={self.component_id}, issue_type={self.issue_type}, issue_id={self.issue_id}, notes={self.notes})>"
6161
)
6262

63+
class LowSeverityAuditResult(Base):
64+
__tablename__ = "low_severity_audit_result"
65+
id: Mapped[int] = mapped_column(primary_key=True)
66+
repo: Mapped[str]
67+
component_id = Column(Integer, ForeignKey("application.id", ondelete="CASCADE"))
68+
result_id = Column(Integer, ForeignKey("audit_result.id", ondelete="CASCADE"))
69+
reason: Mapped[str] = mapped_column(Text)
70+
71+
def __repr__(self):
72+
return (
73+
f"<LowSeverityAuditResult(id={self.id}, repo={self.repo}, "
74+
f"component_id={self.component_id}, result_id={self.result_id}, reason={self.reason})>"
75+
)
6376

6477
class EntryPoint(Base):
6578
__tablename__ = "entry_point"
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# SPDX-FileCopyrightText: 2025 GitHub
2+
# SPDX-License-Identifier: MIT
3+
4+
seclab-taskflow-agent:
5+
filetype: taskflow
6+
version: "1.0"
7+
8+
model_config: seclab_taskflows.configs.model_config
9+
10+
globals:
11+
repo:
12+
taskflow:
13+
- task:
14+
must_complete: true
15+
exclude_from_context: true
16+
agents:
17+
- seclab_taskflow_agent.personalities.assistant
18+
model: general_tasks
19+
user_prompt: |
20+
Fetch the vulnerable issues in {{ globals.repo }}.
21+
toolboxes:
22+
- seclab_taskflows.toolboxes.repo_context
23+
- task:
24+
must_complete: true
25+
repeat_prompt: true
26+
async: true
27+
agents:
28+
- seclab_taskflows.personalities.web_application_security_expert
29+
model: code_analysis
30+
toolboxes:
31+
- seclab_taskflows.toolboxes.repo_context
32+
- seclab_taskflows.toolboxes.local_file_viewer
33+
user_prompt: |
34+
The audit result has id {{ result.result_id }}. It is in the component with id {{ result.component_id }}
35+
at the location {{ result.location }}. It is in the repository {{ result.repo }}.
36+
The notes for the audit result are as follows:
37+
38+
{{ result.notes }}
39+
40+
Determine the low severity results based on the following criteria:
41+
- blind SSRF that has limited on the information it discloses. For example, an SSRF that only gives a different
42+
HTTP status for a specific type of endpoint and rejects all other endpoints (e.g. the endpoint must respond with a certain type of payload), and does not disclose any information other than the HTTP status code.
43+
- Path traversal or partial path traversal that can only read access to a specific directory with limited types of files (e.g. it can only access log files, or it can only access files with a specific extension).
44+
- Path traversal or partial path traversal that only discloses the existence of files or directories, and does not disclose any additional information about the file or directory.
45+
- Information disclosure that only discloses whether a specific condition is true, or some
46+
id number, publicly available resources, such as source code files or documentation,
47+
and does not disclose any additional information. For example, an information disclosure that only discloses whether a specific user exists,
48+
or an information disclosure that only discloses whether a specific issue id exists in the system.
49+
- Issues that requires a malicious admin users to exploit during installation, configuration or other
50+
set up process.
51+
- When running CLI tools or installers, we assume the user already has control on the device.
52+
Any issues that only allows a local user to gain access of the device with running these tools or during installation
53+
is considered low severity.
54+
However, do not exclude issues in installation or configuration that can be exploited by non-admin users.
55+
- CSRF or XSS issues that can only be exploited during a very specific time window. For example,
56+
CSRF or XSS that can only be exploited during the installation process.
57+
- Stored XSS that requires an admin user to upload malicious contents.
58+
- Issue with very limited impact, such as
59+
forcing a user to log out, rate limiting, DoS issues.
60+
- Misclassified issues that does not have a valid attack scenario or impact.
61+
- Issues that requires knowledge of the victim's private information (e.g. secret tokens, private keys, credentials)
62+
in order to exploit.
63+
- Issues that requires physical access to the device or system, or sharing a device with the victim.
64+
- Blind SQL injection that does not return any data, and only returns a different HTTP status code for a specific type of endpoint, and does not disclose any information other than the HTTP status code.
65+
66+
If you decided to reject an issue, provide the reason, and then
67+
store a low severity reason for the result with the id {{ result.result_id }}. Otherwise,
68+
you can finish the task.
69+
70+
DO NOT change or store anything for the current audit result.
71+
72+
73+

0 commit comments

Comments
 (0)