diff --git a/component_catalog/migrations/0016_alter_component_vcs_url_alter_package_download_url_and_more.py b/component_catalog/migrations/0016_alter_component_vcs_url_alter_package_download_url_and_more.py
new file mode 100644
index 00000000..2492bfa6
--- /dev/null
+++ b/component_catalog/migrations/0016_alter_component_vcs_url_alter_package_download_url_and_more.py
@@ -0,0 +1,30 @@
+# Generated by Django 6.1.1 on 2026-10-09 07:47
+
+import django.core.validators
+import re
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('component_catalog', '0015_component_latest_non_vulnerable_version_and_more'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='component',
+ name='vcs_url',
+ field=models.CharField(blank=True, help_text='URL to the Version Control System (VCS).', max_length=1024, validators=[django.core.validators.RegexValidator(re.compile('^[\\w+.-]+://[\\S]+$'), code='invalid', message='Enter a valid URI.')], verbose_name='VCS URL'),
+ ),
+ migrations.AlterField(
+ model_name='package',
+ name='download_url',
+ field=models.CharField(blank=True, help_text='The download URL for obtaining the package.', max_length=1024, validators=[django.core.validators.RegexValidator(re.compile('^[\\w+.-]+://[\\S]+$'), code='invalid', message='Enter a valid URI.')], verbose_name='Download URL'),
+ ),
+ migrations.AlterField(
+ model_name='package',
+ name='vcs_url',
+ field=models.CharField(blank=True, help_text='URL to the Version Control System (VCS).', max_length=1024, validators=[django.core.validators.RegexValidator(re.compile('^[\\w+.-]+://[\\S]+$'), code='invalid', message='Enter a valid URI.')], verbose_name='VCS URL'),
+ ),
+ ]
diff --git a/component_catalog/templates/component_catalog/includes/vulnerability_info_menu.html b/component_catalog/templates/component_catalog/includes/vulnerability_info_menu.html
index e6e4e0d6..37c17a50 100644
--- a/component_catalog/templates/component_catalog/includes/vulnerability_info_menu.html
+++ b/component_catalog/templates/component_catalog/includes/vulnerability_info_menu.html
@@ -16,10 +16,15 @@
{% endfor %}
{% endif %}
- {% if vulnerability.highest_ssvc_decision %}
+ {% if vulnerability.highest_ssvc_decision or vulnerability.datasource_id %}
{% if vulnerability.aliases %}
{% endif %}
-
SSVC: {{ vulnerability.highest_ssvc_decision }}
+ {% if vulnerability.highest_ssvc_decision %}
+
SSVC: {{ vulnerability.highest_ssvc_decision }}
+ {% endif %}
+ {% if vulnerability.datasource_id %}
+
{% trans "Source" %}: {{ vulnerability.datasource_id }}
+ {% endif %}
{% endif %}
diff --git a/docs/howto-7-vulnerability-triage-configuration.rst b/docs/howto-7-vulnerability-triage-configuration.rst
index 3e2ed513..fd62cd45 100644
--- a/docs/howto-7-vulnerability-triage-configuration.rst
+++ b/docs/howto-7-vulnerability-triage-configuration.rst
@@ -53,6 +53,9 @@ Below the base fields, each built-in rule appears as a collapsible section.
restrict detection by weighted package exposure.
- **Stale Vulnerability**: set :guilabel:`Max days` (default 30) and
:guilabel:`Min risk score` (default 8.0).
+ - **Advisory Source**: set :guilabel:`Datasource ids` to a comma-separated list of
+ VulnerableCode datasource IDs (e.g., ``ghsa, nvd``). The rule matches nothing until
+ at least one ID is set.
A ruleset must have at least one rule enabled to produce any triage records.
diff --git a/docs/reference-vulnerability-management.rst b/docs/reference-vulnerability-management.rst
index c67f0e93..8cedef84 100644
--- a/docs/reference-vulnerability-management.rst
+++ b/docs/reference-vulnerability-management.rst
@@ -125,6 +125,9 @@ The **Vulnerability** model in DejaCode provides detailed information about soft
vulnerabilities. Each field captures specific aspects of a vulnerability, enabling
accurate assessment and management. Below is a description of the key fields:
+- **datasource_id**:
+ The VulnerableCode datasource that provided the advisory. For example, **"ghsa"**.
+
- **advisory_id**:
A unique identifier for the vulnerability. For example, **"PYSEC-2020-2233"**.
diff --git a/docs/reference-vulnerability-triage.rst b/docs/reference-vulnerability-triage.rst
index 225b3a8b..bfee7af6 100644
--- a/docs/reference-vulnerability-triage.rst
+++ b/docs/reference-vulnerability-triage.rst
@@ -19,7 +19,7 @@ that are relevant to its security program via the **Admin** interface.
Built-in Rules
--------------
-Eight rules are available out of the box. Each rule implements a specific detection
+Nine rules are available out of the box. Each rule implements a specific detection
condition evaluated against the vulnerabilities known to affect the product's packages.
.. list-table::
@@ -64,6 +64,12 @@ condition evaluated against the vulnerabilities known to affect the product's pa
| ``dev_only_vulnerable_package``
- Detects vulnerabilities that exclusively affect packages marked as non-deployed
in the product, indicating a lower exposure risk.
+ * - | **Advisory Source**
+ | ``advisory_source``
+ - Detects vulnerabilities reported by one of the configured VulnerableCode
+ datasources. Use it to prioritize trusted sources, or, combined with the highest
+ precedence and an analysis preset (e.g., ``false_positive``), to dismiss the
+ advisories of a source.
.. seealso::
Refer to :ref:`reference_vulnerability_management` for background on vulnerability
@@ -92,6 +98,12 @@ The following parameters are supported by rules that accept them:
- ``min_risk_score`` (float, 0.0-10.0): only consider vulnerabilities whose risk score
is greater than or equal to this value. Defaults to ``8.0``.
+**Advisory Source** (``advisory_source``)
+
+- ``datasource_ids`` (list of strings): VulnerableCode datasource IDs to match, such as
+ ``ghsa`` or ``nvd``. Entered as a comma-separated list. Defaults to an empty list,
+ which matches nothing.
+
Triage Actions
--------------
diff --git a/product_portfolio/migrations/0020_alter_product_vcs_url_and_more.py b/product_portfolio/migrations/0020_alter_product_vcs_url_and_more.py
new file mode 100644
index 00000000..8d4fc304
--- /dev/null
+++ b/product_portfolio/migrations/0020_alter_product_vcs_url_and_more.py
@@ -0,0 +1,25 @@
+# Generated by Django 6.1.1 on 2026-10-09 07:47
+
+import django.core.validators
+import re
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('product_portfolio', '0019_productaffectedbyvulnerability_detected_date'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='product',
+ name='vcs_url',
+ field=models.CharField(blank=True, help_text='URL to the Version Control System (VCS).', max_length=1024, validators=[django.core.validators.RegexValidator(re.compile('^[\\w+.-]+://[\\S]+$'), code='invalid', message='Enter a valid URI.')], verbose_name='VCS URL'),
+ ),
+ migrations.AlterField(
+ model_name='productcomponent',
+ name='download_url',
+ field=models.CharField(blank=True, help_text='URL to the source of the Component Package. Once validated this should point to a Package. If you identified a DejaCode Component in the "component" field, and if it already has a Package defined with the download_url, then this is not necessary.', max_length=1024, validators=[django.core.validators.RegexValidator(re.compile('^[\\w+.-]+://[\\S]+$'), code='invalid', message='Enter a valid URI.')], verbose_name='Download URL'),
+ ),
+ ]
diff --git a/product_portfolio/templates/product_portfolio/tabs/tab_packages_vulnerabilities.html b/product_portfolio/templates/product_portfolio/tabs/tab_packages_vulnerabilities.html
index a6c67d15..bab8be54 100644
--- a/product_portfolio/templates/product_portfolio/tabs/tab_packages_vulnerabilities.html
+++ b/product_portfolio/templates/product_portfolio/tabs/tab_packages_vulnerabilities.html
@@ -84,9 +84,9 @@
{% else %}
{{ vulnerability.advisory_id }}
{% endif %}
- {% if vulnerability.aliases or vulnerability.highest_ssvc_decision %}
-
-