{"id":29791392,"url":"https://github.com/hazcod/shade","last_synced_at":"2025-10-14T07:06:01.364Z","repository":{"id":302609536,"uuid":"1012493918","full_name":"hazcod/shade","owner":"hazcod","description":"PoC shadow SaaS and insecure credential detection system using a browser extension.","archived":false,"fork":false,"pushed_at":"2025-08-07T20:46:22.000Z","size":7794,"stargazers_count":40,"open_issues_count":1,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-10-01T06:51:29.951Z","etag":null,"topics":["hibp","identity","saas","shadow"],"latest_commit_sha":null,"homepage":"","language":"Go","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/hazcod.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-02T12:19:54.000Z","updated_at":"2025-09-08T19:35:44.000Z","dependencies_parsed_at":"2025-07-03T09:50:07.497Z","dependency_job_id":null,"html_url":"https://github.com/hazcod/shade","commit_stats":null,"previous_names":["hazcod/shade"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/hazcod/shade","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hazcod%2Fshade","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hazcod%2Fshade/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hazcod%2Fshade/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hazcod%2Fshade/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hazcod","download_url":"https://codeload.github.com/hazcod/shade/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hazcod%2Fshade/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279018208,"owners_count":26086303,"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-10-14T02:00:06.444Z","response_time":60,"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":["hibp","identity","saas","shadow"],"created_at":"2025-07-28T00:16:03.202Z","updated_at":"2025-10-14T07:06:01.358Z","avatar_url":"https://github.com/hazcod.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# shade\n\nA system for detecting shadow SaaS and securely recording the credentials used.\u003cbr/\u003e\nThe system consists of a Go API backend and a browser extension written in TypeScript.\n\nThe extension communicates to a backend:\n\n![Concept diagram](.github/img/concept.png)\n\nAnd very roughly looks like this:\n\n![UI screenshot](.github/img/dashboard.png)\n\nAnd integrates with HaveIBeenPwned to check your passwords (in a secure way):\n\n![HIBP integration warning](.github/img/hibp-warning.png)\n\n## How does it work?\n\nThe browser extension is deployed to your company browsers with a secret token.\nUsing this token, the extension will now report any login events to a web (SaaS) application of that user to the backend.\nOnly events using the correct secret user token and username filter will be processed.\nA typical use case is only processing email usernames for the company domain.\nEvery password entry will be matched to [HIBPs k-Anonymity model for password checking](https://haveibeenpwned.com/API/v3#SearchingPwnedPasswordsByRange). \n\nThe Chrome extension configuration profile looks like this:\n```json\n{\n  \"filters\": [\"domain.com\"],\n  \"locked\": true,\n  \"api\": \"http://localhost:8080\",\n  \"id\": \"\",\n  \"enabled\": true,\n  \"token\": \"\"\n}\n```\n\nConfiguration options:\n- **filters**: Array of domains to filter for in usernames (e.g., company domain)\n- **locked**: Whether users can change settings (recommended: true for production)\n- **api**: Backend server URL\n- **id**: Unique device identifier (auto-generated if empty)\n- **enabled**: Enable/disable the extension\n- **token**: Secret authentication token for backend communication\n\nAnd an example configuration file for the Go backend:\n```yaml\nlog:\n  level: info\n\nhttp:\n    port: 8080\n    interface: 0.0.0.0\n\nstorage:\n    type: memory\n    properties:\n      token: YOUR-LONG-SECRET-TOKEN-VALUE-HERE\n```\nWhich you could run with `shade -config=dev.yml`.\n\n## Project Structure\n\n- `backend/`: Go backend server\n- `extension/`: Chrome extension\n\n## Building the Project\n\nThe project includes a Makefile to simplify building and cleaning both the backend and extension.\n\n### Makefile Commands\n\n```bash\n# build the extension and run the server locally\n% make dev\n\n# Build both the backend and extension\n% make\n\n# Clean up build artifacts\n% make clean\n```\n\n## Backend\n\nThe backend is a Go HTTP server that provides API endpoints for receiving and storing login data.\n\n### Features\n\n- Receives login data from the Chrome extension\n- Stores login data in memory (can be extended to use a database)\n- Provides endpoints for retrieving login data and statistics\n\n### API Endpoints\n\n- `GET /api/health`: Health check endpoint (e.g. to verify browser extension token)\n- `POST /api/creds/register`: Registers a login event for the user (user, domain, password hash)\n- `POST /api/password/domaincheck`: Verifies if the user password is being shared across other websites\n- `GET /api/password/compromised`: Returns compromised passwords from HIBP database\n\n### Web Dashboard\n\nThe backend provides a comprehensive web dashboard accessible at `/dashboard/` with the following pages:\n\n- **Dashboard** (`/dashboard/`): Overview with statistics cards showing total users, domains, duplicate passwords, and users without MFA\n- **Discovered SaaS** (`/dashboard/saas`): Table view of all discovered SaaS applications with search/filter functionality\n- **Password Security** (`/dashboard/security`): Shows users with duplicate passwords and users without MFA\n- **Enrolled Users** (`/dashboard/users`): Lists all enrolled users with their device tokens, hostnames, IP addresses, and last seen timestamps\n\n### Authentication\n\nThe web dashboard supports multiple authentication providers:\n- **Local Authentication**: Username/password authentication with configurable users\n- **OIDC**: OpenID Connect integration for enterprise SSO\n\n### HIBP Integration\n\nThe backend integrates with Have I Been Pwned (HIBP) to check password security:\n- **Real-time Checking**: Every login event is checked against HIBP database\n- **Caching**: Results are cached for 1 hour to improve performance\n- **Bulk Checking**: Scheduled checks every 8 hours for all stored passwords\n- **Privacy-Preserving**: Uses k-anonymity model - only first 5 characters of SHA-1 hash are sent\n- **User Notifications**: Extension shows warnings when breached passwords are detected\n\n## Chrome Extension\n\nThe Chrome extension detects login events on web pages and sends the data to the backend.\n\n### Features\n\n- **Login Detection**: Automatically detects login forms and submissions on web pages\n- **MFA Support**: Detects multi-factor authentication fields (TOTP, SMS codes) including support for multi-step login flows\n- **Success Validation**: Only sends login data for successful authentication attempts, filtering out failed logins\n- **Data Capture**: Captures domain, username, password hash, MFA status, client IP, and hostname\n- **HIBP Notifications**: Shows real-time warnings when passwords are found in breach databases\n- **Device Tracking**: Assigns unique device IDs and tracks real client information\n- **Configuration UI**: Popup interface for settings with API testing and test page access\n- **Privacy-First**: Passwords are hashed locally using SHA-512 before transmission\n\n### Building the Extension\n\n```bash\n# Option 1: Build manually\ncd extension\n\n# Install dependencies\nnpm install\n\n# Build the extension\nnpm run build\n\n# Option 2: Build using the Makefile\nmake extension\n```\n\n### Loading the Extension in Chrome\n\n1. Open Chrome and navigate to `chrome://extensions`\n2. Enable \"Developer mode\" (toggle in the top-right corner)\n3. Click \"Load unpacked\" and select the `extension` directory\n4. The extension should now be installed and active\n\n### Configuration\n\nClick on the extension icon in the Chrome toolbar to open the popup UI. From there, you can:\n# Shade - Password Security Monitoring\n\nShade is a tool for monitoring password security across multiple services. It detects and reports duplicate password usage across different services and can provide insights into password security risks.\n\n## Features\n\n- Track password usage across multiple services\n- Detect duplicate password usage\n- Web dashboard for monitoring\n- Multiple authentication provider support (Local, OIDC)\n- API for integration with other services\n\n## Authentication\n\nShade supports multiple authentication providers:\n\n1. **Local Authentication**: Username/password authentication against a local configuration\n2. **OIDC Authentication**: Single Sign-On using any OpenID Connect provider (Google, Okta, Auth0, etc.)\n\n### Configuration\n\nAuthentication is configured in the `config.yaml` file:\n\n```yaml\nauth:\n  type: \"local\"  # or \"oidc\"\n  secret: \"your-session-secret\"\n  properties:\n    # For local auth:\n    users:\n      - username: \"admin\"\n        password_hash: \"$2a$10$...\"\n        email: \"admin@example.com\"\n        roles: [\"admin\"]\n\n    # For OIDC auth:\n    provider_url: \"https://accounts.google.com\"\n    client_id: \"your-client-id\"\n    client_secret: \"your-client-secret\"\n    redirect_url: \"http://localhost:8080/auth/callback\"\n    scopes: [\"profile\", \"email\"]\n```\n\n## Installation\n\n1. Clone the repository\n2. Copy `config.example.yaml` to `config.yaml` and configure it for your environment\n3. Build and run the application\n\n```bash\ngo build -o shade ./cmd\n./shade -config config.yaml\n```\n\n## Usage\n\nOnce the server is running, you can access the dashboard at `http://localhost:8080`.\n\nYou'll need to log in using credentials configured in the config file (for local auth) or via your OIDC provider (for OIDC auth).\n\n## API\n\nAll API endpoints require authentication:\n\n- `GET /api/health` - Check the health of the system\n- `POST /api/login/register` - Register a new login event\n- `GET /api/password/domaincheck` - Check for duplicate password usage\n\n## Local development\n\n1. Build the extension with `make extension`.\n2. Run the local server with `make`.\n3. Load the extension via 'Load unpacked extension' from `chrome://extensions`.\n4. Open the extension page in Chrome, click on `Inspect views` and configure the extension there:\n```js\nchrome.storage.local.set({ config: { filters:[], locked: true, api: 'http://localhost:8080', id: '1', enabled: true, token: 'foo' } }, () =\u003e {\n    console.log(\"Config saved.\");\n}); \n```\n5. Open up the embedded test page at [chrome-extension://ppkdjdnjclkkfmkflkpibohckapebacn/test-login.html](chrome-extension://ppkdjdnjclkkfmkflkpibohckapebacn/test-login.html)\n\n## Development and Testing\n\n### Test Pages\n\nThe project includes several test pages for development and validation:\n\n- **test_login_success.html**: Tests login success/failure detection with simulated scenarios\n- **test_multistep_login.html**: Tests multi-step authentication flows and MFA detection\n- **Extension Test Page**: Accessible via \"Open Test Page\" button in extension popup\n\n### Webpack Configuration\n\nThe extension uses webpack with environment-specific optimizations:\n\n```bash\n# Development build (unminified for debugging)\nnpm run build -- --mode=development\n\n# Production build (minified and optimized)\nnpm run build -- --mode=production\n```\n\n### MFA Detection\n\nThe extension automatically detects various MFA field types:\n- **TOTP Fields**: Numeric inputs with patterns like `totp`, `mfa`, `code`, `token`\n- **Multi-step Flows**: Waits for MFA fields to appear after initial login\n- **Generic Detection**: Uses common MFA field patterns that work across different websites\n- **Field Characteristics**: Detects based on maxLength, autocomplete, and inputMode attributes\n\n## License\n\n[License information]\n- Enable/disable the extension\n- Set the backend API URL\n- View the device ID\n\n## How It Works\n\n1. The Chrome extension injects a content script into all web pages\n2. The content script monitors for login forms and submissions\n3. When a login event is detected, the content script captures the domain, username, and password\n4. The data is sent to the background script\n5. The background script adds the device ID and sends the data to the backend\n6. The backend stores the data and provides endpoints for retrieving it\n\n## Security Considerations\n\n- The extension stores sensitive data (passwords) temporarily in memory\n- The backend stores login data in memory (in a production environment, this would be replaced with a secure database)\n- Communication between the extension and backend should be secured with HTTPS in a production environment\n- The device ID is used to identify the source of the login data\n\n## Testing the Extension\n\nTo test the Chrome extension and verify it's working correctly, follow these steps:\n\n### Prerequisites\n\n1. Make sure the backend server is running:\n   ```bash\n   # Start the backend server\n   ./shade\n   ```\n\n2. Ensure the extension is loaded in Chrome (as described in \"Loading the Extension in Chrome\" section)\n\n### Testing Steps\n\n1. **Verify the extension is loaded properly**:\n   - Check that the extension icon appears in Chrome's toolbar\n   - Click on the icon to open the popup UI\n   - Verify that the configuration options are displayed correctly\n   - Check that the Device ID is generated and displayed\n\n2. **Configure the extension**:\n   - In the popup UI, ensure the \"Backend API URL\" is set to where your backend is running (default: `http://localhost:8080`)\n   - Make sure the extension is enabled (toggle should be on)\n   - Click \"Save Settings\" to apply the configuration\n\n3. **Test login detection**:\n   - **Option 1**: Use the included test page\n     - Open the `extension/test-login.html` file in Chrome\n     - Fill in the form with test credentials\n     - Submit the form\n     - Check the Console for messages from the extension\n\n   - **Option 2**: Use any website with a login form\n     - Open a new tab and navigate to a website with a login form\n     - Open Chrome DevTools by right-clicking on the page and selecting \"Inspect\"\n     - Go to the \"Console\" tab in DevTools\n     - Fill in the login form with test credentials (username and password)\n     - Submit the form\n     - Check the Console for messages like \"Login detected on [domain] for user [username]\"\n\n4. **Verify data is sent to the backend**:\n   - After submitting a login form, check the backend server logs for messages indicating that login data was received\n   - You can also verify by querying the backend API:\n     ```bash\n     # Get your device ID from the extension popup\n     # Then use it to query the backend\n     curl http://localhost:8080/api/logins?device_id=YOUR_DEVICE_ID\n     ```\n   - Check the response to see if your test login was recorded\n\n5. **Check overall statistics**:\n   ```bash\n   curl http://localhost:8080/api/stats\n   ```\n   This should show the total number of logins detected and unique devices.\n\n### Debugging Tips\n\nIf the extension isn't working as expected:\n\n1. **Check the extension logs**:\n   - Open Chrome DevTools for the background script:\n     - Go to `chrome://extensions`\n     - Find the Login Detector extension\n     - Click \"service worker\" under \"Inspect views\"\n     - Check the Console for any error messages\n\n2. **Verify content script injection**:\n   - When on a page with a login form, open Chrome DevTools\n   - Go to the \"Sources\" tab\n   - Expand the \"Content scripts\" section\n   - Verify that the extension's content script is listed\n\n3. **Test with a simple login form**:\n   - Create a simple HTML file with a basic login form for testing:\n     ```html\n     \u003c!DOCTYPE html\u003e\n     \u003chtml\u003e\n     \u003chead\u003e\n       \u003ctitle\u003eLogin Test\u003c/title\u003e\n     \u003c/head\u003e\n     \u003cbody\u003e\n       \u003cform id=\"login-form\"\u003e\n         \u003cinput type=\"text\" name=\"username\" placeholder=\"Username\"\u003e\n         \u003cinput type=\"password\" name=\"password\" placeholder=\"Password\"\u003e\n         \u003cbutton type=\"submit\"\u003eLogin\u003c/button\u003e\n       \u003c/form\u003e\n       \u003cscript\u003e\n         document.getElementById('login-form').addEventListener('submit', function(e) {\n           e.preventDefault();\n           alert('Form submitted!');\n         });\n       \u003c/script\u003e\n     \u003c/body\u003e\n     \u003c/html\u003e\n     ```\n   - Open this file in Chrome and test the login detection\n\n4. **Check backend connectivity**:\n   - Verify the backend server is running and accessible\n   - Check that the API URL in the extension configuration is correct\n   - Test the backend API directly using curl or a tool like Postman\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhazcod%2Fshade","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhazcod%2Fshade","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhazcod%2Fshade/lists"}