{"id":30356598,"url":"https://github.com/specterops/snowhound","last_synced_at":"2025-08-19T06:13:10.974Z","repository":{"id":307878913,"uuid":"1025196900","full_name":"SpecterOps/SnowHound","owner":"SpecterOps","description":null,"archived":false,"fork":false,"pushed_at":"2025-08-11T19:05:56.000Z","size":997,"stargazers_count":11,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-08-11T21:08:14.348Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"PowerShell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/SpecterOps.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-07-23T22:12:47.000Z","updated_at":"2025-08-11T19:05:59.000Z","dependencies_parsed_at":"2025-08-02T20:51:07.909Z","dependency_job_id":null,"html_url":"https://github.com/SpecterOps/SnowHound","commit_stats":null,"previous_names":["specterops/snowhound"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/SpecterOps/SnowHound","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SpecterOps%2FSnowHound","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SpecterOps%2FSnowHound/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SpecterOps%2FSnowHound/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SpecterOps%2FSnowHound/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SpecterOps","download_url":"https://codeload.github.com/SpecterOps/SnowHound/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SpecterOps%2FSnowHound/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":271108837,"owners_count":24700584,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-19T02:00:09.176Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-08-19T06:13:10.328Z","updated_at":"2025-08-19T06:13:10.958Z","avatar_url":"https://github.com/SpecterOps.png","language":"PowerShell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# SnowHound\n\n![](./images/snowhound-example.png)\n\n## Overview\n\nThe BloodHound extension for Snowflake provides a powerful way to visualize access control and potential attack paths within a Snowflake environment. By mapping key entities such as Users, Roles, Databases, Warehouses, and Integrations, along with the permissions that connect them, this extension enables security teams to gain a comprehensive understanding of their Snowflake landscape. The extension leverages Snowflake’s Role-Based Access Control (RBAC) model, allowing organizations to identify and address attack paths in their Snowflake tenants. With this tool, users can explore how access is granted, track potential attack paths, and implement effective security strategies to mitigate risk in their Snowflake accounts.\n\nI recommend reading my [Mapping Snowflake's Access Landscape](https://specterops.io/blog/2024/06/13/mapping-snowflakes-access-landscape/) blogpost from June of 2024 to understand why Snowflake was interesting to me and to understand some of the types of questions that we can begin to ask with this model.\n\n## Collector Setup \u0026 Usage\n\nNOTE: I expect that over time we will develop a more robust/specific collector for SNOWHound, but in the short term it seemed simpler to leverage Snowflake's fantastic query interface.\n\n### Collecting Data\n\nThe first step is to collect the graph-relevant data from Snowflake. The cool thing is that this is actually a relatively simple process. I’ve found that Snowflake’s default web client, Snowsight, does a fine job gathering this information. You can navigate to Snowsight once you’ve logged in by clicking on the Query data button at the top of the Home page.\n\n![](./images/snowsight.webp)\n\nOnce there, you will have the opportunity to execute commands. This section will describe the commands that collect the data necessary to build the graph. My parsing script is built for CSV files that follow a specific naming convention. Once your command has returned results, click the download button (downward pointing arrow) and select the “Download as .csv” option.\n\n![](./images/query.webp)\n\nThe model supports Accounts, Applications, Databases, Roles, Users, and Warehouses. This means we will have to query those entities, which will serve as the nodes in our graph. This will download the file with a name related to your account. My parsing script expects the output of certain commands to be named in a specific way. The expected name will be shared in the corresponding sections below.\n\nI’ve found that I can query Applications, Databases, Roles, and Users as an unprivileged user. However, this is different for Accounts, which require ORGADMIN, and Warehouses, which require instance-specific access (e.g., [ACCOUNTADMIN](https://docs.snowflake.com/en/user-guide/warehouses-tasks#delegating-warehouse-management)).\n\n#### Accounts\n\n* Command: [SELECT * FROM snowflake.organization_usage.accounts WHERE account_locator = CURRENT_ACCOUNT();](https://docs.snowflake.com/en/sql-reference/sql/show-accounts)\n* File Name: accounts.csv\n\n#### Applications\n\n* Command: [SHOW APPLICATIONS;](https://docs.snowflake.com/en/sql-reference/sql/show-applications)\n* File Name: applications.csv\n\n#### Databases\n\n* Command: [SELECT * FROM snowflake.account_usage.databases;](https://docs.snowflake.com/en/sql-reference/sql/show-databases)\n* File Name: databases.csv\n\n#### Schemas\n\n* Command: [SHOW SCHEMAS;](https://docs.snowflake.com/en/sql-reference/sql/show-schemas)\n* File Name: schemas.csv\n\n#### Roles\n\n* Command: [SELECT * FROM snowflake.account_usage.roles;](https://docs.snowflake.com/en/sql-reference/sql/show-roles)\n* File Name: roles.csv\n\n#### Users\n\n* Command: [SELECT * FROM snowflake.account_usage.users;](https://docs.snowflake.com/en/sql-reference/sql/show-users)\n* File Name: users.csv\n\n#### Warehouses\n\n* Command: [SHOW WAREHOUSES;](https://docs.snowflake.com/en/sql-reference/sql/show-warehouses)\n* File Name: warehouses.csv\n\nNote: As mentioned above, users can only enumerate warehouses for which they have been granted privileges. One way to grant a non-ACCOUNTADMIN user visibility of all warehouses is to grant the [MANAGE WAREHOUSES](https://docs.snowflake.com/en/user-guide/warehouses-tasks#delegating-warehouse-management) privilege.\n\n#### Integrations\n\n* Command: [SHOW INTEGRATIONS;](https://docs.snowflake.com/en/sql-reference/sql/show-integrations)\n* File Name: integrations.csv\n\n#### Grants\n\nFinally, we must gather information on privilege grants. These are maintained in the ACCOUNT_USAGE schema of the default SNOWFLAKE database. By default, these views are only available to the ACCOUNTADMIN role. Still, users not granted USAGE of the ACCOUNTADMIN role can be granted the necessary read access via the [SECURITY_VIEWER](https://docs.snowflake.com/en/sql-reference/account-usage#account-usage-views-by-database-role) database role. The following command does this (if run as ACCOUNTADMIN):\n\n```\nGRANT DATABASE ROLE snowflake.SECURITY_VIEWER TO \u003cRole\u003e\n```\n\nOnce you have the necessary privilege, you can query the relevant views and export them to a CSV file. The first view is [grants_to_users](https://docs.snowflake.com/en/sql-reference/account-usage/grants_to_users), which maintains a list of which roles have been granted to which users. You can enumerate this list using the following command. Then save it to a CSV file and rename it grants_to_users.csv.\n\n```\nSELECT * FROM snowflake.account_usage.grants_to_users;\n```\n\nThe final view is [grants_to_roles](https://docs.snowflake.com/en/sql-reference/account-usage/grants_to_roles), which maintains a list of all the privileges granted to roles. This glue ultimately allows users to interact with the different Snowflake entities. This view can be enumerated using the following command. The results should be saved as a CSV file named grants_to_roles.csv.\n\n```\nSELECT * FROM snowflake.account_usage.grants_to_roles WHERE GRANTED_ON IN ('ACCOUNT', 'APPLICATION', 'DATABASE', 'INTEGRATION', 'ROLE', 'SCHEMA', 'USER', 'WAREHOUSE');\n```\n\n### Generating BloodHound OpenGraph Payload\n\nAfter you've collected the relevant data from your Snowflake tenant, you must convert it from csv to a BloodHound OpenGraph payload. This is done via the [snowhound.ps1](./snowhound.ps1) script found in this repository.\n\n1) In a PowerShell terminal, navigate to the folder where the Snowflake csv files are located.\n\n2) Load snowhound.ps1 into your PowerShell session:\n\n```powershell\n. ./snowhound.ps1\n```\n\n3) Execute the Invoke-SnowHound function:\n\n```powershell\nInvoke-SnowHound\n```\n\nSnowHound will output a payload to your current working directory called `snowhound_output.json`\n\n4) Upload the payload via BloodHound's File Ingest page\n\n### Sample\nIf you do not have a Snowflake environment or if you want to test out Snowhound before collecting from your own production environment, we've included a sample data set at ./samples/example.json.\n\n## Schema\n\nThe schema defines the structure and relationships between various entities in the Snowflake environment, which are critical for mapping access and attack paths. In this extension, the schema consists of several key node types, including SNOWAccount, SNOWUser, SNOWRole, SNOWWarehouse, SNOWDatabase, and SNOWIntegration. These nodes are interconnected through edges that represent permissions, access grants, and roles, showing how users and services interact with Snowflake resources.\n\nThe schema allows you to visualize the relationships between users, roles, databases, and other entities in your Snowflake account, providing a comprehensive view of your environment’s security posture. By defining these entities and their permissions, the schema enables you to identify potential attack paths, privilege escalation opportunities, and access risks. Each node type is linked through explicit access permissions, ensuring a clear mapping of how users and roles can exploit vulnerabilities or gain access to sensitive data.\n\n![Snowflake Schema](./images/snowflake_schema.png)\n\nBelow is the complete set of nodes and edges as defined in the [model](./model.json).\n\n### Nodes\n\nNodes correspond to each object type.\n\n| Node                                                                           | Description                                                                                                                                | Icon        | Color   |\n|--------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------|-------------|---------|\n| \u003cimg src=\"./images/black_SNOWAccount.svg\" width=\"30\"/\u003e SNOWAccount             | The top-level container for all Snowflake resources such as users, roles, databases, and integrations.                                     | building    | #5FED83 |\n| \u003cimg src=\"./images/black_SNOWApplication.svg\" width=\"30\"/\u003e SNOWApplication     | | window-maximize | #A1C6EA |\n| \u003cimg src=\"./images/black_SNOWDatabase.svg\" width=\"30\"/\u003e SNOWDatabase           | Represents a Snowflake database, linked to users, roles, and warehouses that have access to it.                                            | database    | #FF80D2 |\n| \u003cimg src=\"./images/black_SNOWIntegration.svg\" width=\"30\"/\u003e SNOWIntegration     | Represents an integration with an external system or service in Snowflake, such as a data pipeline or third-party application.             | user-tie    | #BFFFD1 |\n| \u003cimg src=\"./images/black_SNOWRole.svg\" width=\"30\"/\u003e SNOWRole                   | Represents a role in Snowflake that defines a set of permissions, which can be assigned to users or other roles.                           | user-group  | #C06EFF |\n| \u003cimg src=\"./images/black_SNOWSchema.svg\" width=\"30\"/\u003e SNOWSchema               | | network-wired | #DEFEFA |\n| \u003cimg src=\"./images/black_SNOWUser.svg\" width=\"30\"/\u003e SNOWUser                   | Represents an individual user in a Snowflake account, linked to roles, warehouses, and databases that define their access.                 | user        | #FF8E40 |\n| \u003cimg src=\"./images/black_SNOWWarehouse.svg\" width=\"30\"/\u003e SNOWWarehouse         | Represents a Snowflake virtual warehouse providing computational resources for running queries, with access controlled by roles and users. | warehouse   | #9EECFF |\n\n### Edges\n\nEdges capture every relationship; who contains what, membership, view vs. manage permissions, etc.\n\nNOTE: I need to go back and add SNOWContains edges from the SNOWAccount to all of the components of the account.\nNOTE: I need to go back and document all of the edges to and from SNOWApplication and SNOWSchema nodes.\n\n| Edge Type                         | Source            | Target            | Travesable |\n|-----------------------------------|-------------------|-------------------| ---------- |\n| `SNOWUsage`                       | `SNOWApplication` | `SNOWDatabase`    | y          |\n| `SNOWUsage`                       | `SNOWRole`        | `SNOWDatabase`    | y          |\n| `SNOWUsage`                       | `SNOWRole`        | `SNOWIntegration` | y          |\n| `SNOWUsage`                       | `SNOWRole`        | `SNOWRole`        | y          |\n| `SNOWUsage`                       | `SNOWRole`        | `SNOWUser`        | y          |\n| `SNOWUsage`                       | `SNOWRole`        | `SNOWWarehouse`   | y          |\n| `SNOWOwnership`                   | `SNOWRole`        | `SNOWDatabase`    | y          |\n| `SNOWOwnership`                   | `SNOWRole`        | `SNOWIntegration` | y          |\n| `SNOWOwnership`                   | `SNOWRole`        | `SNOWRole`        | y          |\n| `SNOWOwnership`                   | `SNOWRole`        | `SNOWUser`        | y          |\n| `SNOWOwnership`                   | `SNOWRole`        | `SNOWWarehouse`   | y          |\n| `SNOWApplyBudget`                 | `SNOWRole`        | `SNOWDatabase`    | n          |\n| `SNOWApplyBudget`                 | `SNOWRole`        | `SNOWWarehouse`   | n          |\n| `SNOWAudit`                       | `SNOWRole`        | `SNOWAccount`     | n          |\n| `SNOWModify`                      | `SNOWRole`        | `SNOWDatabase`    | n          |\n| `SNOWModify`                      | `SNOWRole`        | `SNOWWarehouse`   | n          |\n| `SNOWMonitor`                     | `SNOWRole`        | `SNOWAccount`     | n          |\n| `SNOWMonitor`                     | `SNOWRole`        | `SNOWDatabase`    | n          |\n| `SNOWMonitor`                     | `SNOWRole`        | `SNOWWarehouse`   | n          |\n| `SNOWOperate`                     | `SNOWRole`        | `SNOWWarehouse`   | n          |\n| `SNOWApplyAggregationPolicy`      | `SNOWRole`        | `SNOWAccount`     | n          |\n| `SNOWApplyAuthenticationPolicy`   | `SNOWRole`        | `SNOWAccount`     | n          |\n| `SNOWApplyMaskingPolicy`          | `SNOWRole`        | `SNOWAccount`     | n          |\n| `SNOWApplyPackagesPolicy`         | `SNOWRole`        | `SNOWAccount`     | n          |\n| `SNOWApplyPasswordPolicy`         | `SNOWRole`        | `SNOWAccount`     | n          |\n| `SNOWApplyProtectionPolicy`       | `SNOWRole`        | `SNOWAccount`     | n          |\n| `SNOWApplyRowAccessPolicy`        | `SNOWRole`        | `SNOWAccount`     | n          |\n| `SNOWApplySessionPolicy`          | `SNOWRole`        | `SNOWAccount`     | n          |\n| `SNOWAttachPolicy`                | `SNOWRole`        | `SNOWAccount`     | n          |\n| `SNOWBindServiceEndpoint`         | `SNOWRole`        | `SNOWAccount`     | n          |\n| `SNOWCancelQuery`                 | `SNOWRole`        | `SNOWAccount`     | n          |\n| `SNOWCreateAccount`               | `SNOWRole`        | `SNOWAccount`     | n          |\n| `SNOWCreateApiIntegration`        | `SNOWRole`        | `SNOWAccount`     | n          |\n| `SNOWCreateApplication`           | `SNOWRole`        | `SNOWAccount`     | n          |\n| `SNOWCreateApplicationPackage`    | `SNOWRole`        | `SNOWAccount`     | n          |\n| `SNOWCreateComputerPool`          | `SNOWRole`        | `SNOWAccount`     | n          |\n| `SNOWCreateCredential`            | `SNOWRole`        | `SNOWAccount`     | n          |\n| `SNOWCreateDataExchangeListing`   | `SNOWRole`        | `SNOWAccount`     | n          |\n| `SNOWCreateDatabase`              | `SNOWRole`        | `SNOWAccount`     | n          |\n| `SNOWCreateDatabaseRole`          | `SNOWRole`        | `SNOWDatabase`    | n          |\n| `SNOWCreateExternalVolume`        | `SNOWRole`        | `SNOWAccount`     | n          |\n| `SNOWCreateIntegration`           | `SNOWRole`        | `SNOWAccount`     | n          |\n| `SNOWCreateNetworkPolicy`         | `SNOWRole`        | `SNOWAccount`     | n          |\n| `SNOWCreateReplicationGroup`      | `SNOWRole`        | `SNOWAccount`     | n          |\n| `SNOWCreateRole`                  | `SNOWRole`        | `SNOWAccount`     | n          |\n| `SNOWCreateSchema`                | `SNOWRole`        | `SNOWDatabase`    | n          |\n| `SNOWCreateShare`                 | `SNOWRole`        | `SNOWAccount`     | n          |\n| `SNOWCreateUser`                  | `SNOWRole`        | `SNOWAccount`     | n          |\n| `SNOWCreateWarehouse`             | `SNOWRole`        | `SNOWAccount`     | n          |\n| `SNOWExecuteDataMetricFunction`   | `SNOWRole`        | `SNOWAccount`     | n          |\n| `SNOWExecuteManagedAlert`         | `SNOWRole`        | `SNOWAccount`     | n          |\n| `SNOWExecuteManagedTask`          | `SNOWApplication` | `SNOWAccount`     | n          |\n| `SNOWExecuteManagedTask`          | `SNOWRole`        | `SNOWAccount`     | n          |\n| `SNOWExecuteTask`                 | `SNOWApplication` | `SNOWAccount`     | n          |\n| `SNOWExecuteTask`                 | `SNOWRole`        | `SNOWAccount`     | n          |\n| `SNOWImportShare`                 | `SNOWRole`        | `SNOWAccount`     | n          |\n| `SNOWManageGrants`                | `SNOWRole`        | `SNOWAccount`     | n          |\n| `SNOWManageWarehouses`            | `SNOWRole`        | `SNOWAccount`     | n          |\n| `SNOWManagementSharing`           | `SNOWRole`        | `SNOWAccount`     | n          |\n| `SNOWMonitorExecution`            | `SNOWRole`        | `SNOWAccount`     | n          |\n| `SNOWOverrideShareRestrictions`   | `SNOWRole`        | `SNOWAccount`     | n          |\n| `SNOWPurchaseDataExchangeListing` | `SNOWRole`        | `SNOWAccount`     | n          |\n| `SNOWReferenceUsage`              | `SNOWRole`        | `SNOWDatabase`    | n          |\n| `SNOWUseAnyRole`                  | `SNOWRole`        | `SNOWIntegration` | n          |\n\n### To Do\n\n- Add support for detailed information on integrations, specifically security integrations associated with SCIM or SSO (type = `SCIM - *` or `SAML2`)\n- Add support for more detailed objects such as Application Roles (these currently show up as unknown objects)\n\n## Contributing\n\nWe welcome and appreciate your contributions! To make the process smooth and efficient, please follow these steps:\n\n1. **Discuss Your Idea**  \n   - If you’ve found a bug or want to propose a new feature, please start by opening an issue in this repo. Describe the problem or enhancement clearly so we can discuss the best approach.\n\n2. **Fork \u0026 Create a Branch**  \n   - Fork this repository to your own account.  \n   - Create a topic branch for your work:\n     ```bash\n     git checkout -b feat/my-new-feature\n     ```\n\n3. **Implement \u0026 Test**  \n   - Follow the existing style and patterns in the repo.  \n   - Add or update any tests/examples to cover your changes.  \n   - Verify your code runs as expected:\n     ```bash\n     # e.g. dot-source the collector and run it, or load the model.json in BloodHound\n     ```\n\n4. **Submit a Pull Request**  \n   - Push your branch to your fork:\n     ```bash\n     git push origin feat/my-new-feature\n     ```  \n   - Open a Pull Request against the `main` branch of this repository.  \n   - In your PR description, please include:\n     - **What** you’ve changed and **why**.  \n     - **How** to reproduce/test your changes.\n\n5. **Review \u0026 Merge**  \n   - I’ll review your PR, give feedback if needed, and merge once everything checks out.  \n   - For larger or more complex changes, review may take a little longer—thanks in advance for your patience!\n\nThank you for helping improve this extension! 🎉  \n\n## Licensing\n\n```\nCopyright 2025 Jared Atkinson\n\nLicensed under the Apache License, Version 2.0\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n    http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n```\n\nUnless otherwise annotated by a lower-level LICENSE file or license header, all files in this repository are released\nunder the `Apache-2.0` license. A full copy of the license may be found in the top-level [LICENSE](LICENSE) file.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fspecterops%2Fsnowhound","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fspecterops%2Fsnowhound","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fspecterops%2Fsnowhound/lists"}