BidWritePro is built for federal contractors, who operate under high standards of data protection, audit, and compliance. This page describes the technical and organizational security measures in place today, what we’re working on, and how to report security concerns.
Passwords are hashed with bcrypt at a cost factor of 12. We never store passwords in plain text. Legacy SHA-256 hashes (from earlier versions) are silently upgraded to bcrypt the next time the user signs in.
New passwords must be at least 10 characters and contain a digit or symbol, or be at least 14 characters. The most common compromised passwords are blocked. Password resets follow the same rules.
The login endpoint pays the same bcrypt cost on the user-not-found path as on a real user with a wrong password. This prevents timing-side-channel username enumeration.
Each account permits one active session at a time. Signing in from a new device automatically invalidates any prior session, ensuring stolen tokens have a finite useful life.
Session tokens are persisted server-side in PostgreSQL with a bounded TTL (currently 30 days). Logout invalidates the token immediately. Tokens are random 32-byte values generated with the operating system’s cryptographic entropy source.
Authentication endpoints are rate-limited per IP address and per username:
All communication with the Service uses HTTPS with TLS 1.2 or higher. HTTP requests are redirected to HTTPS at the load balancer.
Our PostgreSQL database is hosted on infrastructure that provides storage-layer encryption at rest using AES-256.
Uploaded documents (RFPs, amendments, proposals, exports) are stored either in AWS S3 with server-side encryption (SSE-S3 or SSE-KMS), or, in fallback configurations, on the application’s host disk with the same storage-layer encryption as the database. S3 keys are scoped per user.
Every database query that returns user data is scoped by the requesting user’s ID. Cross-user access is blocked at the application layer. Compliance matrices, proposals, saved solicitations, profiles, audit logs, and document records are all per-user.
When AWS S3 is the storage backend, every uploaded document is stored under a per-user prefix. Pre-signed URLs for download have a short TTL (5 minutes by default) and are issued only after the user is authenticated and the document is confirmed to belong to them.
Compliance matrices generated from RFPs are stored both in the user’s proposal record (PostgreSQL) and, for short-term cache convenience, on disk with a filename prefix that includes the user ID. Cross-tenant access via the disk fallback was eliminated as part of pre-launch hardening.
Uploaded files are subject to a 25 MB hard cap (covers every legitimate federal RFP we’ve tested against). Content-Length is checked before reading the body to prevent OOM attacks. MIME type and extension are both validated against an allowlist (PDF, DOCX, DOC, TXT). Rejection returns 413 (oversize) or 415 (wrong type).
PDF and Word text extraction is performed by external command-line tools (pdftotext, pandoc) running in subprocess isolation. Uploaded files are written to disk under randomized UUID filenames; they are never executed.
All database access is via SQLAlchemy ORM with parameterized queries. Raw SQL is used only in two carefully-reviewed places (advisory locks for digest scheduling and the password-hash column-widening migration), both with bound parameters. No string-concatenated SQL.
The frontend is React, which escapes user-supplied content by default. Outbound URLs from the API to <a href> are filtered through an allow-list of safe schemes (http/https/mailto/tel/relative); javascript: and data: schemes are blocked. Email digest content is HTML-escaped before assembly.
Authentication uses bearer tokens stored in the browser’s localStorage. Tokens are not sent automatically by the browser the way cookies are, removing the standard CSRF attack surface. Cross-origin requests are restricted by a tightened CORS policy: explicit method allowlist, explicit header allowlist, origin allowlist that includes only the production domain.
User-supplied document text is wrapped in delimited tags before being sent to the AI vendor, and the AI is given an explicit instruction to treat the document body as data, not as instructions. This reduces the surface for adversarial document content steering the AI.
Server errors return generic messages to the client. Real exception detail is logged server-side with type and message but never echoed in the API response, removing a class of information-disclosure leaks.
Every login, logout, password reset, registration, document upload, RFP parse, proposal generation, admin user action, and manual digest send is recorded in an audit log with timestamp, actor, target, and a short description. The audit log is accessible to admin users from the Admin Console.
We do not log passwords, full session tokens, full document content, full prompts, or full AI responses. We do log the metadata that allows incident investigation (file size, parse outcome, request count) without the body content itself.
Subscription billing is processed by Stripe, a PCI-DSS Level 1 service provider. Card numbers and CVVs are entered directly into Stripe’s secure form; they never touch our servers. We receive only a Stripe customer ID, subscription metadata, and (for receipts) the last four digits of the card.
Stripe webhooks are verified using the signed-secret HMAC scheme. Unsigned, malformed, or replayed webhook events are rejected.
The administrator account is seeded only when the ADMIN_PASSWORD environment variable is set. If it is missing, the account seeder generates a one-time random password, prints it to the deploy log, and refuses to ship a guessable default. The site-gate password is similarly env-driven, with no fallback.
BidWritePro relies on a small number of carefully-selected vendors. See our Privacy Policy for the full list. Highlights:
SOC 2 Type II audit readiness is on our 2026 roadmap. The technical practices on this page were designed with SOC 2 control objectives in mind. We will publish the report and an executive summary when available.
BidWritePro is hosted on commercial cloud infrastructure that is not FedRAMP-authorized for the storage or processing of classified information, Controlled Unclassified Information (CUI), or other restricted federal data categories. Do not upload material in those categories. See the corresponding clause in our Terms of Service.
All BidWritePro infrastructure (application servers, PostgreSQL, S3 storage) is hosted in the United States. We do not currently support EU/UK data residency.
If you believe you’ve found a security vulnerability in BidWritePro, please report it responsibly to [email protected] with the subject line “Security Disclosure”. Include:
We commit to:
Please do not test for vulnerabilities against accounts other than your own, and please do not access, modify, or exfiltrate data belonging to other users in the course of any test.
If a security incident affects your data, we will notify affected users by email at the address on file as soon as we have a substantiated, accurate understanding of the incident. Notifications will include the nature of the incident, the data affected, the steps we’ve taken in response, and the steps you should take. We follow applicable U.S. state breach-notification timelines, which generally require notification within 30 to 60 days of confirmation, depending on the state.
For security questions, vulnerability reports, or audit/compliance documentation requests:
Cortexis Group, LLC
Attn: Security
13611 South Dixie Highway, Suite 453
Miami, Florida 33176
United States
Email: [email protected]