Matt du Jardin
Matt du Jardin
Founder · May 20, 2026 · 7 min read
Security

What We Hardened in Auth and Privacy This Week

Passkeys, server-side AAL2 gating on TOTP disable, GDPR cookie consent, a broader data export, and audit logs across auth, billing, account, and team routes. A plain-language recap of what changed and why.

Vendor contracts contain sensitive commercial terms. Pricing, notice periods, counterparty names, payment schedules. When you upload one to Renewly, you are trusting us with that information. This past week we shipped a focused batch of auth and privacy changes. No new features - just closing gaps we had identified in how accounts are secured, how data is scoped between tenants, and how GDPR obligations are met.

Passkeys Are Now Available

You can now register a passkey from your account security settings. Touch ID, Face ID, or a hardware security key such as a YubiKey or Titan Key - any WebAuthn-compatible authenticator works. You can register more than one passkey, give each a name, and revoke individual passkeys without touching the others.

Passkeys are phishing-resistant by construction. A passkey is cryptographically bound to renewly.gg. It cannot be used on a lookalike domain. It cannot be extracted and replayed the way a TOTP code can be. This is the standard the industry is moving toward and we wanted it available to anyone who holds a vendor contract portfolio on the platform.

Magic Links With Rate Limiting by Intent

Renewly has always been passwordless - there is no stored password on your account to leak or brute-force. This week we completed work ensuring every magic-link request runs through a server-side rate limiter with separate budgets per intent: 10 attempts per 15 minutes for login, 5 for signup, 3 for password reset.

Previously the browser could call the auth provider directly and bypass the edge limiter entirely. The server-side route closes that gap. The auth provider's own per-email rate limit still applies as a second layer.

Magic link redirects are now validated against a trusted origin allowlist. A link generated for the production domain cannot be redirected to an external host via a manipulated Host header.

Disabling TOTP Now Requires a Second Authentication Step

TOTP two-factor authentication has been available in Renewly for a while. There was a gap: the disable path ran in the browser without requiring the user to re-authenticate at a higher assurance level.

The risk: if an attacker gained access to an active session - stolen cookie, compromised device - they could disable 2FA without ever knowing the TOTP secret, then change the email address or export contract data.

The fix moves the disable call to a server-side route that enforces AAL2 (Authentication Assurance Level 2) before proceeding. To disable TOTP, you now need to complete a second factor. A session-hijacked attacker at the lower assurance level cannot disable your 2FA.

Org Data Does Not Bleed Into Personal Views

Renewly supports both solo accounts and team workspaces. The rule: once a user joins an organization, they see only that organization's contracts. No personal contracts and no other organizations' data appear in the same view.

The original dashboard code showed personal contracts alongside org contracts for org members, inflating counts and leaking context across the boundary. We fixed it across six surfaces: the dashboard, contracts list, calendar, iCal export, CSV export, and the top-nav search.

Analytics queries are now scoped through a per-session contract ID whitelist. A member of one organization cannot cause the analytics endpoint to return aggregate data from a different tenant, even with a crafted request.

Workspace switching is validated server-side. Attempting to switch to an organization you are not a member of is rejected at the API layer, not just hidden in the client UI.

Audit Logging Extended Across Auth, Billing, and Team Routes

We had audit logging on contract operations and billing events. We extended it this week to cover:

  • Authentication events: login, logout, MFA enable and disable, passkey registration and revocation, session revocation
  • Account events: profile updates, data exports, deletion requests and cancellations
  • Settings changes: notification preferences, cookie preferences
  • Team events: invitations sent, declined and accepted, role changes
  • Vendor actions: opt-outs, opt-back-ins, alert acknowledgements and dismissals
  • Workspace switches

Audit logs are retained for 3 years. Your own audit log is included in any data export you request.

Non-Essential Trackers Are Now Consent-Gated

Until this week, analytics and session recording loaded on first visit without asking. That was not compliant with GDPR Article 7, which requires freely given, informed, and specific consent before non-essential tracking can begin.

The fix: a consent banner on first visit. Third-party analytics trackers do not load unless you accept. Crisp live chat is not gated because it is a functional support service, not a marketing tool.

You can change your choice at any time from Settings - Account - Cookie Preferences. That is the GDPR Article 7(3) affordance: consent must be as easy to withdraw as it was to give.

Data Export Now Covers 16 Categories

The GDPR Article 15 data export now covers 16 categories: profile, account, contracts and extracted data, tags, contract-tag associations, notifications, preferences, audit logs, account deletion requests, inbox aliases, inbox messages, vendor signal alerts, vendor signal opt-outs, user sessions, calendar integrations, and webhook endpoints.

Credential material - OAuth tokens, webhook secrets - is redacted from the export. You get the configuration data but not the secrets themselves. The export is available from Settings at any time with no support request required.

Stripe Billing Is Now Tied to User ID, Not Just Email

Stripe customer records now carry a userId field in their metadata, set at checkout creation. Webhook handlers verify this binding first. The practical effect: a billing event for customer A cannot be applied to account B even if they share an email address. The binding is tamper-proof at the Stripe side and validated on every webhook.

What This Adds Up To

Vendor contracts sit at the intersection of commercial sensitivity and operational dependency. You cannot cancel a vendor because you missed the notice window. You cannot renegotiate terms you cannot find. If the contract data leaks before a renewal, you have lost negotiating leverage before the conversation starts.

Getting the security baseline right is not a feature. It is the minimum for something this close to your vendor relationships. The full breakdown is on the security page.

https://renewly.gg #vendorcontracts #contractmanagement #security

Never Miss a Vendor Renewal

Upload a vendor contract and get every renewal date, notice window, and auto-renewal clause extracted in seconds. Free for 5 contracts.

Start Free