diff --git a/CHANGELOG.md b/CHANGELOG.md
index fb2c7de..d0657b9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,55 @@
CHANGELOG
VINCE Coordination platform code
+
+## Description
+VINCE Coordination platform code
+
+Version 3.0.21 2025-06-30
+
+* updated numerous links to CVD documentation, etc. (Internal-816)
+* added logging for the authentication process (Internal-817)
+* modified specifications for spreadsheet used for detailed weekly reports to CISA (Internal-804)
+
+
+Version 3.0.20 2025-06-11
+
+* fixed bug affecting redirect after editing case vulnerability information (Internal-810)
+* added filtering for the Edit Case form to prevent inactive users from appearing as potential case owners (Internal-811)
+* reinstated API endpoints turned off in last release; added database model for logging certain API endpoint access events (Internal-812)
+* dependabot update recommendations: `django` 4.2.21 to 4.2.22, `requests` 2.32.0 to 2.32.4
+
+
+Version 3.0.19 2025-05-06
+
+* Turned off certain API endpoints for security review (Internal-807)
+* Updated code for CSV files in response to user requests for more fine-grained information (Internal-804)
+* Updated link to VINCE Documentation (Internal-808)
+
+
+Version 3.0.18 2025-04-17
+
+* Updated code for CSV files in reponse to even more user requests for more fine-grained information (Internal-804)
+
+
+Version 3.0.17 2025-04-17
+
+* Updated code for CSV files in reponse to user requests for more fine-grained information (Internal-804)
+
+
+Version 3.0.16 2025-04-17
+
+* dependabot update recommendations: `Django` 4.2.17 to 4.2.20, `python-jose` 3.3.0 to 3.4.0
+* Fixed bug preventing certain users from changing their passwords (Internal-800)
+* Tweaked logs for Internal-791
+* Added code for CSV files to support preparation of reports for CISA (Internal-804)
+
+
+Version 3.0.15 2025-03-17
+
+* Modified code for checking authenticity so as to include extra logs and to bypass false negatives (Internal-791)
+
+
Version 3.0.14 2025-03-17
* Added code for checking authenticity of emails subject to new preprocessing for AWS email integration (Internal-791)
diff --git a/README.md b/README.md
index ab6d3d1..10044a5 100644
--- a/README.md
+++ b/README.md
@@ -13,9 +13,9 @@ Mellon University.
* The CERT Guide to Coordinated Vulnerability Disclosure: [https://vuls.cert.org/confluence/display/CVD](https://vuls.cert.org/confluence/display/CVD)
* Report a Vulnerability [https://www.kb.cert.org/vuls/report/](https://www.kb.cert.org/vuls/report/)
-* VINCE User Documentation: [https://vuls.cert.org/confluence/display/VIN/VINCE+Documentation](https://vuls.cert.org/confluence/display/VIN/VINCE+Documentation)
-* Vulnerability Note API Documentation: [https://vuls.cert.org/confluence/display/VIN/Vulnerability+Note+API](https://vuls.cert.org/confluence/display/VIN/Vulnerability+Note+API)
-* VINCE API Documentation: [https://vuls.cert.org/confluence/display/VIN/VINCE+API](https://vuls.cert.org/confluence/display/VIN/VINCE+API)
+* VINCE User Documentation: [https://certcc.github.io/VINCE-docs/](https://certcc.github.io/VINCE-docs/)
+* Vulnerability Note API Documentation: [https://certcc.github.io/VINCE-docs/Vulnerability-Note-API/](https://certcc.github.io/VINCE-docs/Vulnerability-Note-API/)
+* VINCE API Documentation: [https://certcc.github.io/VINCE-docs/VINCE-API/](https://certcc.github.io/VINCE-docs/VINCE-API/)
### Bugs and Feature Requests
@@ -74,7 +74,6 @@ reduce the risk of exposure.
[](https://github.com/CERTCC/VINCE/raw/main/Vince_Infrastructure.png)
-
### Local Install
1. Clone the repo
diff --git a/bigvince/settings_.py b/bigvince/settings_.py
index 82fef99..59d5e0c 100644
--- a/bigvince/settings_.py
+++ b/bigvince/settings_.py
@@ -54,7 +54,7 @@
ROOT_DIR = environ.Path(__file__) - 3
# any change that requires database migrations is a minor release
-VERSION = "3.0.14"
+VERSION = "3.0.21"
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/2.1/howto/deployment/checklist/
diff --git a/cogauth/backend.py b/cogauth/backend.py
index 7fd521b..17a6264 100644
--- a/cogauth/backend.py
+++ b/cogauth/backend.py
@@ -134,6 +134,7 @@ class CognitoAuthenticate(ModelBackend):
def authenticate(self, request, username=None, password=None):
ip = vinceutils.get_ip(request)
if username and password:
+ logger.debug(f"CognitoAuthenticate is running with username {username}")
cognito_user = CognitoUser(
settings.COGNITO_USER_POOL_ID,
settings.COGNITO_APP_ID,
@@ -147,10 +148,12 @@ def authenticate(self, request, username=None, password=None):
logger.debug(f"trying to authenticate {username} from IP {ip}")
cognito_user.authenticate(password)
except ForceChangePasswordException:
+ logger.debug(f"ForceChangePasswordException when trying to authenticate {username} from IP {ip}")
request.session["FORCEPASSWORD"] = True
request.session["username"] = username
return None
except SoftwareTokenException as e:
+ logger.debug(f"SoftwareTokenException {e} when trying to authenticate {username} from IP {ip}")
request.session["MFAREQUIRED"] = "SOFTWARE_TOKEN_MFA"
request.session["username"] = username
request.session["MFASession"] = cognito_user.session
@@ -158,6 +161,7 @@ def authenticate(self, request, username=None, password=None):
request.session.save()
return None
except SMSMFAException:
+ logger.debug(f"SMSMFAException when trying to authenticate {username} from IP {ip}")
request.session["MFAREQUIRED"] = "SMS_MFA"
request.session["username"] = username
request.session["MFASession"] = cognito_user.session
@@ -194,6 +198,7 @@ def authenticate(self, request, username=None, password=None):
# emails for username - so get email and return CognitoUser
email = list(filter(lambda email: email["Name"] == "email", user["UserAttributes"]))[0]["Value"]
username = email
+ logger.debug(f"CognitoAuthenticate is running on an ACCESS_TOKEN. username is {username}")
cognito_user = CognitoUser(
settings.COGNITO_USER_POOL_ID,
settings.COGNITO_APP_ID,
@@ -207,6 +212,9 @@ def authenticate(self, request, username=None, password=None):
cognito_user.refresh_token = request.session["REFRESH_TOKEN"]
else:
+ logger.debug(
+ "CognitoAuthenticate is running, but it has not found a username/password pair or an ACCESS_TOKEN."
+ )
headers = {"Content-Type": "application/x-www-form-urlencoded"}
data = {
"grant_type": "authorization_code",
@@ -237,6 +245,9 @@ def authenticate(self, request, username=None, password=None):
)
user = client.get_user(AccessToken=access_token)
username = user["Username"]
+ logger.debug(
+ f"CognitoAuthenticate is running, but it has not found a username/password pair or an ACCESS_TOKEN. Nevertheless, username has been found to be {username}"
+ )
cognito_user = CognitoUser(
settings.COGNITO_USER_POOL_ID,
settings.COGNITO_APP_ID,
diff --git a/cogauth/views.py b/cogauth/views.py
index 6d43154..d471f71 100644
--- a/cogauth/views.py
+++ b/cogauth/views.py
@@ -838,6 +838,7 @@ def form_valid(self, form):
self.request.session["ACCESS_TOKEN"] = tokens["AuthenticationResult"]["AccessToken"]
user = authenticate(self.request, username=self.request.session["username"])
if user:
+ logger.debug(f"user {user} is trying to use the MFA Required screen")
del self.request.session["username"]
auth_login(self.request, user)
self.cognito = get_cognito(self.request)
@@ -863,8 +864,10 @@ def form_valid(self, form):
logger.debug(f"NEXT URL provided by GET request {next_url}")
try:
if is_safe_url(next_url, set(settings.ALLOWED_HOSTS), True):
+ logger.debug(f"{user} wants to access {next_url}, and it has been found to be safe")
return redirect(next_url)
else:
+ logger.debug(f"{user} wants to access {next_url}, and it has not been found to be safe")
return redirect(settings.LOGIN_REDIRECT_URL)
except Exception as e:
logger.debug(f"Error in redirection validator {e}")
@@ -1004,14 +1007,16 @@ def form_valid(self, form):
ip = vinceutils.get_ip(self.request)
try:
c.change_password(form.cleaned_data["old_password"], form.cleaned_data["new_password1"])
- logger.info(f"Password was updated for {self.request.username} from IP {ip}")
+ logger.info(f"Password was updated for {self.request.user.username} from IP {ip}")
except ParamValidationError:
- logger.info(f"Password updated failed for {self.request.username} from IP {ip} - invalid new password")
+ logger.info(
+ f"Password updated failed for {self.request.user.username} from IP {ip} - invalid new password"
+ )
form._errors.setdefault("new_password1", ErrorList(["New password is unacceptable."]))
return super().form_invalid(form)
except (Boto3Error, ClientError) as e:
error_code = e.response["Error"]["Code"]
- logger.info(f"Password updated failed for {self.request.username} from IP {ip} - {e} {error_code}")
+ logger.info(f"Password updated failed for {self.request.user.username} from IP {ip} - {e} {error_code}")
if error_code == "NotAuthorizedException":
form._errors.setdefault("old_password", ErrorList(["Password is incorrect."]))
return super().form_invalid(form)
diff --git a/requirements.txt b/requirements.txt
index bfd20f5..a4f8099 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -24,7 +24,7 @@ cryptography==44.0.1
cvelib==1.3.0
Deprecated==1.2.13
dictdiffer==0.9.0
-Django==4.2.17
+Django==4.2.22
django-appconf==1.0.5
django-countries==7.4.2
django-environ==0.9.0
@@ -63,12 +63,12 @@ pyparsing==3.0.9
pyrsistent==0.19.2
python-dateutil==2.8.2
python-gnupg==0.5.0
-python-jose==3.3.0
+python-jose==3.4.0
pytz==2022.6
PyYAML==5.4.1
qrcode==7.3.1
redis==4.5.4
-requests==2.32.0
+requests==2.32.4
rsa==4.7.2
s3transfer==0.6.0
segno==1.5.2
diff --git a/vince/forms.py b/vince/forms.py
index 83552b9..2682e06 100644
--- a/vince/forms.py
+++ b/vince/forms.py
@@ -1699,10 +1699,15 @@ class Meta:
def get_group_choices(self, user):
return [(q.id, q.name) for q in user.groups.exclude(groupsettings__contact__isnull=True)]
+ def get_owner_choices(self):
+
+ return [(u.id, u.email) for u in User.objects.using("default").filter(is_active=True)]
+
def __init__(self, *args, **kwargs):
user = kwargs.pop("user")
super(EditCaseForm, self).__init__(*args, **kwargs)
self.fields["team_owner"].choices = self.get_group_choices(user)
+ self.fields["owner"].choices = self.get_owner_choices()
class AssignTicketTeamForm(forms.Form):
diff --git a/vince/lib.py b/vince/lib.py
index 29cf719..5c91e14 100644
--- a/vince/lib.py
+++ b/vince/lib.py
@@ -2364,7 +2364,7 @@ def verify_authenticity_header(msg, key, headers):
match = hmac.compare_digest(value, expected_value)
if not match:
logger.warn(
- "match did not happen correctly. expected_value is {expected_value} and actual value is {value}"
+ f"match did not happen correctly. expected_value is {expected_value} and actual value is {value}"
)
return match
@@ -3152,6 +3152,8 @@ def prepare_and_send_weekly_report():
week = oneweekago.isocalendar()[1]
weekstartdate = date.fromisocalendar(year, week, 1)
weekenddate = date.fromisocalendar(year, week, 7)
+ # for testing:
+ # daterangeend = datetime.now()
daterangeend = weekenddate + timedelta(days=1)
# examine the GroupSettings model, looking for groups that have weekly="on"
@@ -3178,6 +3180,7 @@ def prepare_and_send_weekly_report():
ticket__queue__in=my_queues,
).exclude(ticket__case__isnull=False)
tickets = Ticket.objects.filter(queue__in=my_queues, created__range=[weekstartdate, daterangeend])
+ logger.debug(f"when processing the weekly report data, tickets is found to be {tickets}")
closed_tickets = tickets.filter(status=Ticket.CLOSED_STATUS)
new_cases = VulnerabilityCase.objects.filter(
created__range=[weekstartdate, daterangeend], team_owner=my_team
@@ -3219,6 +3222,8 @@ def prepare_and_send_weekly_report():
"case_emails_distinct": case_emails.order_by("ticket__case__id").distinct("ticket__case__id").count(),
"total_emails": ticket_emails.count() + case_emails.count(),
"total_tickets": tickets.count(),
+ "tickets": tickets,
+ "closed_tickets": closed_tickets,
"ticket_stats": tickets.values("queue__title")
.order_by("queue__title")
.annotate(count=Count("queue__title"))
@@ -3247,15 +3252,7 @@ def prepare_and_send_weekly_report():
),
}
- logger.debug("context complete")
- logger.debug("weeklyreport context is")
- logger.debug(context)
-
- # # This is just for testing:
- # # weekstartdate = date.today()
- # # daterangeend = weekstartdate + timedelta(days=1)
- # # context['weekstartdate'] = weekstartdate
- # # context['weekenddate'] = weekstartdate + timedelta(days=1)
+ logger.debug(f"weeklyreport context is {context}")
if groupid == 1:
total_ai_ml_crs = (
diff --git a/vince/templates/vince/base.html b/vince/templates/vince/base.html
index 7afb823..fd448c1 100644
--- a/vince/templates/vince/base.html
+++ b/vince/templates/vince/base.html
@@ -307,7 +307,7 @@
Vulnerability INformation and Coordination Environment
Welcome to the Vulnerability Information and Coordination Environment (VINCE). If you are a vendor and would like to communicate with us about a vulnerability or update your contact information, please create an account or sign in. You can also report a vulnerability to us, with or without a VINCE account.
+
Welcome to the Vulnerability Information and Coordination Environment (VINCE). If you are a vendor and would like to communicate with us about a vulnerability or update your contact information, please create an account or sign in. You can also report a vulnerability to us, with or without a VINCE account. For more information see the VINCE Documentation site.
Create an Account
diff --git a/vince/templates/vince/printweeklyreport.html b/vince/templates/vince/printweeklyreport.html
index 6ca81ab..ef6e9a3 100644
--- a/vince/templates/vince/printweeklyreport.html
+++ b/vince/templates/vince/printweeklyreport.html
@@ -151,26 +151,27 @@
During vulnerability coordination, multiple stakeholders analyze a vulnerability to be able to disclose it to the public and provide guidance on how to mitigate or fix it.
+
+ A vulnerability is difficult to define. It can be thought of as a flaw in software or hardware components that allows an attacker to perform actions that wouldn't normally be allowed. The impact of such vulnerabilities varies greatly. They may allow the attacker to learn someone's private email address, take control of a computer, or even cause physical damage and bodily injury.
+
At CERT/CC, our goal is to coordinate with the various stakeholders and make sure the vulnerability is addressed accordingly and that the correct information reaches the public.
The CERT Division is a leader in cybersecurity. We partner with government, industry, law enforcement, and academia to improve the security and resilience of computer systems and networks. We study problems that have widespread cybersecurity implications and develop advanced methods and tools to counter large-scale, sophisticated cyber threats.
+
+
+
+
+
+
CMU Foundation Theme Usage
+
+
+
+
+
+
+
Here are some examples of the modules contained in the CSS
+
(Here is a Lead Paragraph) The Vulnerability Notes Database contains two types of documents: Vulnerability Notes that describe vulnerabilities that may affect one or more vendors, and Vendor Information documents (also called vendor records), that provide vendor-specific information (e.g., solutions, workarounds, references, and status) about a vulnerability. The fields in each of these documents are described below in more detail.
+
(A Block Quote) Vulnerability Notes that describe vulnerabilities that may affect one or more vendors, and Vendor Information documents (also called vendor records), that provide vendor-specific information (e.g., solutions, workarounds, references, and status) about a vulnerability. The fields in each of these documents are described below in more detail.
Foundation Code Skills These online courses offer you a chance to better understand how Foundation works and how you can master it to create awesome projects.
+
+
+
Foundation Forum Join the Foundation community to ask a question or show off your knowledge.
@zurbfoundation Ping us on Twitter if you have questions. When you build something with this we'd love to see it (and send you a totally boss sticker).
+
+
+
+
+
+
+
+
+
Here’s your basic grid:
+
+
+
+
+
+
This is a twelve column section in a row. Each of these includes a div.callout element so you can see where the columns are - it's not required at all for the grid.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+{% endblock %}
\ No newline at end of file
diff --git a/vincepub/templates/vincepub/index.html b/vincepub/templates/vincepub/index.html
new file mode 100644
index 0000000..c0731db
--- /dev/null
+++ b/vincepub/templates/vincepub/index.html
@@ -0,0 +1,87 @@
+{% extends "vincepub/base.html" %}
+{% load staticfiles %}
+{% block content %}
+
+
+
+
+
+
Vulnerability Notes Database
+
The Vulnerability Notes Database provides information about software vulnerabilities. Vulnerability notes include summaries, technical details, remediation information, and lists of affected vendors. Most vulnerability notes are the result of private coordination and disclosure efforts. For more comprehensive coverage of public vulnerability reports, consider the National Vulnerability Database (NVD). CERT/CC also publishes the Vulnerability Notes Data Archive on GitHub.
+
+
+
+
+
Recently Published Vulnerabilities
+
+ {% for note in pub_list %}
+
+
+ {% with '/vuls/id/'|add:note.idnumber as vul_link %}
+
The CERT/CC Vulnerability Notes Database is run by the CERT Division, which is part of the Software Engineering Institute,
+ a federally funded research and development center operated by Carnegie Mellon University. Together, we are leaders in cybersecurity, software innovation, and computer science.
Search over 3,500 vulnerability notes affecting over 2,300 vendors.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Want to report a vulnerability?
+
The CERT Coordination Center (CERT/CC) prioritizes coordination efforts on vulnerabilities that affect multiple vendors or that impact safety, critical or internet infrastructure, or national security. We also prioritize reports that affect sectors that are new to vulnerability disclosure. We may be able to provide assistance for reports when the coordination process breaks down.
Before reporting any vulnerabilities to the CERT Coordination Center (CERT/CC) and making them public, try contacting the vendor directly. Some vendors offer bug bounty programs.
+
We recommend reading our vulnerability disclosure policy and guidance before submitting a vulnerability report. We send information provided in vulnerability reports to affected vendors.
+
+
CERT/CC does not accept or respond to every report. We prioritize reports that affect multiple vendors or that impact safety, critical or internet infrastructure, or national security. We also prioritize reports that affect sectors that are new to vulnerability disclosure. We may be able to provide assistance for reports when the coordination process breaks down.
Welcome to the Vulnerability Information and Coordination Environment (VINCE). If you are a vendor and would like to communicate with us about a vulnerability or update your contact information, please create an account or sign in. You can also report a vulnerability to us, with or without a VINCE account.
+
Welcome to the Vulnerability Information and Coordination Environment (VINCE). If you are a vendor and would like to communicate with us about a vulnerability or update your contact information, please create an account or sign in. You can also report a vulnerability to us, with or without a VINCE account. For more information see the VINCE Documentation site
Create an Account
diff --git a/vinny/models.py b/vinny/models.py
index 30ca15d..e034000 100644
--- a/vinny/models.py
+++ b/vinny/models.py
@@ -236,12 +236,12 @@ def _get_modified(self):
modified = property(_get_modified)
- #Security issue remove mass unpickling
+ # Security issue remove mass unpickling
def _set_settings(self, data):
# data should always be a Python dictionary.
sdata = {}
- if not isinstance(data,dict):
+ if not isinstance(data, dict):
logger.warn("Non dictionary item sent to settings %s" % str(data))
try:
sdata = json.dumps(data)
@@ -254,12 +254,12 @@ def _get_settings(self):
if self.settings_pickled:
try:
data = json.loads(self.settings_pickled)
- if isinstance(data,dict):
+ if isinstance(data, dict):
return data
else:
logger.warn("Non dictionary item sent to settings %s" % str(data))
except Exception as e:
- logger.warn("Generic error when trying to json parse data %s " %(str(e)))
+ logger.warn("Generic error when trying to json parse data %s " % (str(e)))
return {}
settings = property(_get_settings, _set_settings)
@@ -2112,6 +2112,14 @@ class CaseViewed(models.Model):
date_viewed = models.DateTimeField(default=timezone.now)
+class APIAccess(models.Model):
+ url = models.URLField()
+
+ user = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True, on_delete=models.CASCADE)
+
+ date_viewed = models.DateTimeField(default=timezone.now)
+
+
class CaseCoordinator(models.Model):
case = models.ForeignKey(Case, on_delete=models.CASCADE)
@@ -2189,7 +2197,7 @@ class Status(models.IntegerChoices):
# Admin user or whoever rejected/approved this request.
completed_by = models.CharField(max_length=255, blank=True, null=True)
- expires_at = models.DateTimeField(default=timezone.now() + timedelta(days=30))
+ expires_at = models.DateTimeField(blank=True, null=True)
contact = models.ForeignKey(VinceCommContact, on_delete=models.CASCADE)
thread = models.ForeignKey(Thread, on_delete=models.DO_NOTHING, blank=True, null=True)
@@ -2199,3 +2207,8 @@ class Meta:
def __str__(self):
return f"User approve request for {self.user} to join {self.contact}"
+
+ def save(self, *args, **kwargs):
+ if not self.pk:
+ self.expires_at = timezone.now() + timedelta(days=30)
+ super(UserApproveRequest, self).save(*args, **kwargs)
diff --git a/vinny/templates/vinny/base.html b/vinny/templates/vinny/base.html
index 6c110e9..120e7e2 100644
--- a/vinny/templates/vinny/base.html
+++ b/vinny/templates/vinny/base.html
@@ -147,7 +147,7 @@