AssembleyAssembley

Security & Trust

Built for secure decisions

Assembley is designed from the ground up for governance — where every action must be auditable.

Verifiable secret voting

Secret, and still verifiable.

A secret ballot usually forces a trade: voters can trust the count, or they can verify it — rarely both. Four things are true of a secret ballot here at the same time.

  • The vote row carries no voter identity.
  • A receipt is keyed to the voter, not to the choice.
  • The code that identifies a ballot is derived from a secret held in the voter's browser, never from the emailed token.
  • The tally is independently recomputable from the evidence package.

Identity

Access is a single-use, time-limited ballot link scoped to one voter and one assembly. No passwords, no shared credentials.

Encryption

Connections are encrypted in transit: HTTPS only, HTTP redirected, strict transport security set. Sessions are stored in httpOnly cookies invisible to JavaScript.

Access control

Row-level security separates each organisation's data, and roles separate what a voter and an administrator can reach. On a secret ballot the vote row carries no voter at all.

Infrastructure

The database runs in Frankfurt and the application's functions in the same region. What the sub-processor agreements permit is wider, and two of them name the United States.

Attestation

A hash-chained event log, a Merkle root per agenda item, and an evidence package a third party can recompute without access to our systems.

Monitoring

Administrative actions and governance events are appended to logs whose triggers refuse UPDATE and DELETE. Nothing watches them: the rate limiters refuse abuse, and refusing is not monitoring.

Overview

Assembley handles governance voting for companies, associations, and organisations across Europe. The security model is built around three things: controlled access, vote integrity, and a record that can be checked afterwards.

If a vote is challenged, you can produce the recorded chain of governance events — who voted, when, and in which order. For secret-ballot items the record attests participation and the ballot set, not who chose what. A trigger refuses UPDATE and DELETE on that chain and on the votes themselves, so it cannot be rewritten afterwards by anyone, including Assembley. That is not a policy commitment; it is enforced at the database level.

Identity

Access is a single-use link scoped to one voter and one assembly. No passwords. No shared credentials. What that link is worth is set by the organisation running the assembly.

Integrity

Votes are write-once at the database level. No administrator — including Assembley — can modify or delete a submitted vote.

Auditability

Governance events are recorded with a timestamp and the hash of the one before. The record is self-contained and independently verifiable.

The diagram above shows a single vote moving through Assembley's pipeline. When a voter submits their ballot, the server verifies the session against the assembly, writes the vote, computes a hash of the event, and appends it to the chain. On an identified ballot the vote and its audit entry are written in one database transaction, so neither can exist without the other. A secret ballot is the deliberate exception: it writes no audit entry, because the fields in one would name the voter.

Identity layer

Every participant is identified to the system before a governance action is accepted, and the system does not rely on passwords. What that identification is worth is a setting the organisation chooses.

How magic links work

1
SystemBefore assembly

A unique, cryptographically random ballot link is generated for each voter and sent to their registered email address.

2
VoterDay of assembly

The voter clicks their personal link — no typing, no password, no app required. Works on any device.

3
ServerVerification

The link is validated server-side: checked for expiry, single-use status, and that it belongs to the correct assembly.

4
ServerSingle-use

The link is invalidated on first use — it cannot be forwarded or reused, even if intercepted.

5
ServerSession

A session is issued, stored in an httpOnly cookie invisible to JavaScript, and used to authenticate every subsequent action.

6
BrowserOngoing

The session is re-verified on every vote submission — not just at sign-in.

Identity assurance levels

L1

Self-registration + one-time code

The voter registers themselves and confirms a one-time code sent to their address. A registration matching the roster votes with that member's weight; one that does not waits, and can cast nothing, until the chair admits it as a member.

L2

Magic link + meeting code

The personal link is not enough on its own: the voter must also enter a code shown in the room while the assembly is live.

L3

Magic link + meeting code + electronic ID

An electronic-ID check on top of both. No session is issued until the identity provider has answered — that callback is the only path that mints one.

New assemblies use this ladder. Assemblies created under the earlier scheme keep its five levels, and the level in force is recorded on the assembly and in its evidence package.

Rate limiting

Requests to re-send a ballot link are capped per IP address within a window.

A second link is not sent to the same address for the same assembly inside a cooldown.

One-time codes are capped per email address, with a separate ceiling per address sized for a room full of people on one network.

The re-send path answers identically whether or not the address is on the roster, so it cannot be used to test which addresses exist.

Link security

High-entropy random token — computationally unguessable

Single-use — invalidated immediately on first access

Time-limited — expires automatically after the assembly

Scoped to one assembly — cannot be used elsewhere

Session security

Session cookie is invisible to JavaScript — XSS-resistant

Secure and HTTPS-only under production — cannot be sent over HTTP.

SameSite=Strict, so the cookie is not attached to a request arriving from another site.

Sessions expire automatically — no persistent access

What entry records

Magic-link attempts are recorded with the address, the outcome and the time.

An electronic-ID verification enters the governance chain, carrying the assurance the provider actually returned — including when it returns none.

Entering a meeting code updates a presence row rather than appending an event, so a second entry overwrites the record of the first.

The level of assurance in force is recorded per assembly, not per claim about a person.

Where this stops

  • Assembley does not verify that a person is who the organisation says they are. Which level of assurance applies is the organisation's configuration, and at the lowest level it means only that an address was on a list.

Execution layer

Votes are not stored as rows that get edited. Each is written once, and a trigger refuses UPDATE and DELETE on the table. Results are derived from what was written, not from a running total anyone can adjust.

Event sourcing model

1

Event written

Single INSERT

2

Hash computed

Over event payload

3

Appended to chain

prev_hash included

Vote submission — validation layers

Session verified

The voter's session is verified on every submission — not just at sign-in.

Assembly must be live

Votes are rejected if the assembly has not started or has already ended.

Voting window enforced

The administrator controls exactly when voting opens and closes for each agenda item. No votes are accepted outside this window.

One vote per item

Each voter can submit exactly one vote per agenda item. Duplicate submissions are rejected at the database level, not just in application code.

Vote and audit written together

The vote record and its audit entry are written in a single database transaction. A secret ballot is the exception and writes no audit entry, because the fields in one would name the voter.

A vote cannot be changed or deleted

Once written, a vote cannot be modified or deleted by anyone — including system administrators. This is enforced at the database level, not by access controls alone.

Merkle root updated

After each vote, the Merkle root for the agenda item is recomputed — any modification to any prior vote would change the root.

Event chain integrity

Each audit entry includes the hash of the previous entry — breaking the chain at any point is detectable.

Weighted voting

Each participant carries a voting weight set by the organisation.

Results are calculated on voting weight — not headcount.

Proxy votes are added to the representative's weight.

The administrator sees weighted counts as they arrive.

Administrator-controlled voting windows

Voting opens only when the administrator explicitly opens it

Closes immediately when the administrator moves on

Every voter is pushed the same state over a realtime channel.

Votes submitted outside the window are rejected server-side

What is frozen, and when

When an assembly opens, the figures it will be counted against are frozen: the total voting rights, the share capital basis, the shareholder count, and the quorum configuration. Each agenda item freezes its majority requirement and its secrecy when voting opens on it. The voter's name and weight are frozen onto the ballot as it is written, so a later change to the register cannot rewrite what was cast.

Atomic guarantees

An identified vote and its audit entry are written in a single database transaction; there is no state where one exists without the other. A secret ballot writes the ballot and its receipt in one transaction and no audit entry at all.

Audit layer

Every governance event is appended to a hash-chained log. Tampering with any historical record breaks the chain from that point forward — detectable by any party with access to the log.

Hash chain structure

Event N−1

hash: abc123

Event N

prev: abc123

hash: def456

Event N+1

prev: def456

hash: …

Each event's hash includes the previous hash — forming a tamper-evident chain.

Merkle roots

After voting closes, a Merkle root is computed from all votes

The root is a single hash representing the complete vote set.

Change any vote and the root changes — tampering is detectable

Roots are stored alongside the event chain, in a table whose trigger refuses UPDATE and DELETE.

Evidence package

Generated after the assembly closes

Contains the full event chain, Merkle roots, attendance, and results

The events file is stored uncompressed, so the SHA-256 of those bytes is the Verification ID printed on the PDF.

It carries the stored root, the recomputed root and the leaf scheme per item, so a third party can redo the arithmetic without access to Assembley.

Secret ballots — unattributed, still verifiable

Your own verification receipt

When you cast a secret ballot, your browser shows you a verification code to save. After voting closes, you can find that exact code in the published record and confirm your ballot was counted — without revealing how you voted. The code is deliberately non-transferable: it cannot prove your choice to anyone else, so it gives a vote-buyer or coercer nothing to verify.

Unattributed, verifiable evidence

For a secret item, the evidence package proves the result without naming a single voter: the final tally, the full set of unattributed ballot identifiers, a Merkle root fixing that exact set of ballots, a commitment to who was entitled to vote, and a reconciliation showing the number of ballots equals the number of recorded participants — the check that proves no one voted twice. An outside auditor can verify every line; none of it links a ballot to a person.

Where secrecy has a limit: where shareholders hold very different numbers of shares, an unusually large holding can sometimes be inferred from the published totals. The product says exactly that — on the ballot, before the voter votes. We would rather name the one place secrecy thins out than let it surprise someone later.

Events logged

Voter sign-in

IP address, email address, assembly, outcome, time

Failed sign-in attempt

IP address, email address, time

Vote submitted — identified ballot

Participant, agenda item, choice, IP address, device, time

Vote submitted — secret ballot

Agenda item, ballot code, choice. No voter, no address, no device

Assembly started / ended

Administrator, time

Voting opened / closed

Agenda item, administrator, time

Invitation sent

Recipient, assembly, time

Proxy registered

Grantor, representative, administrator, time

Document exported

Who took a copy, of which assembly, and the hash of what they hold

Where this stops

  • Reading a record is not logged. The log records what was written and what was exported, not who looked at a result or a roster.
  • Nothing watches for unusual activity. The rate limiters refuse abuse, and refusing is a control rather than monitoring — no alert is raised and nobody is notified.

Vote lifecycle

A single vote passes through five deterministic stages. Each stage is independently verifiable.

1

Voter session verified

Magic link token validated server-side, session issued.

2

Voting window confirmed

Server checks the assembly is live and the item is open for voting.

3

Vote event written

A single INSERT. A duplicate is rejected by a database constraint.

4

Audit entry appended

Written in the same transaction as the vote. A secret ballot writes a receipt instead, carrying the voter and not the choice.

5

Merkle root updated

Vote set for this agenda item rehashed and stored.

System trust model

Four precise statements about what the system does. No qualifications, no marketing language.

1

Governance outcomes are not read out of a total anybody can edit. They are derived by replaying the append-only event log.

2

Auditability is architectural. It is not a feature added on top — it is the mechanism by which the system operates.

3

No administrator, including Assembley, can modify or delete a submitted vote. This is enforced at the database level, not by access controls.

4

The evidence package is self-contained. A lawyer or auditor can verify integrity without access to Assembley systems.

Incident transparency

Assembley is designed so that the consequences of a failure are bounded and detectable. Votes are written once and every governance event is hash-chained, so a record altered after the fact breaks the chain at a point any reader can find.

What is watched, and what is not?

Nothing watches for unusual activity and no alert is raised. Failed sign-ins, rate-limit refusals and every administrative action are recorded and visible in the audit trail; reading them is something a person has to do.

What does the evidence package contain?

The full event chain, Merkle roots per agenda item, attendance records, vote results, and timestamps. The events file is stored uncompressed so its SHA-256 is the Verification ID on the PDF, and any modification after generation changes it. It can be verified by a lawyer or auditor without access to Assembley systems.

Can Assembley alter a submitted vote?

No. A trigger blocks UPDATE and DELETE on the votes table at the database level. This applies to every user including Assembley administrators. It is architectural, not a policy.

What happens if Assembley is unavailable?

Evidence packages generated before an outage remain valid and independently verifiable. The record does not depend on Assembley being online to be checked.

Data & privacy

Assembley is built for European organisations. Data is stored in the EU, processed under a data processing agreement, and handled according to data minimisation principles. Where processing may occur is set by the sub-processor agreements rather than by a region setting, and those agreements are summarised in the published sub-processor list.

Data residency

The database runs in AWS eu-central-1, Frankfurt.

The application's functions run in the same region, moved there on 10 September 2026.

Transactional mail is sent from eu-west-1, Ireland.

Two of the three sub-processor agreements state that primary processing takes place in the United States. The sub-processor list carries both the agreement and the console reading, and does not resolve them into one sentence.

Data minimisation

Only the data needed to run an assembly is collected

The Services are designed to run on a name, an email address and a voting entitlement.

No tracking, analytics, or advertising.

Ballot links contain no personal information.

Encryption

All connections are encrypted in transit, with HTTP redirected and strict transport security set for two years.

Passwords, where they are used at all, are held only by the authentication provider and never by this application.

Ballot tokens are stored only as SHA-256 hashes, never in the form that was emailed.

Production credentials are not present in development environments or in anything sent to a browser. Every build counts the database hosts it has inlined and refuses to finish if one of them is not the local stack.

GDPR

The Data Processing Agreement is published, not available on request.

Right to erasure — a request is handled by the organisation as controller, and the share register is deletable by a super admin.

Data portability — full export available

No third-party data sharing without consent

  • Row-level security is enabled on every table, so one organisation's rows are not reachable from another's session.
  • No advertising, no tracking pixels, and no analytics resale.

What each role can access

Participant

What a voter can see

Their own identity and voting weight

The agenda and item descriptions

Their own submitted votes

Whether the assembly is live or ended

Other participants' identities or votes

Results before the assembly ends, where the organisation has chosen to withhold them

Administrative controls or settings

Administrator

What an admin can see

The full participant list with voting weights

Aggregate vote counts as they arrive

Registered presence, and the figures the organisation configured to measure it against

The assembly event log and audit trail

Results after the assembly ends, and exportable minutes

Individual choices in a secret ballot — the ballot row carries no identity to look up

Any change to a vote once submitted

What Assembley does not do

  • No advertising, tracking pixels, or analytics resale — ever.
  • No third-party data sharing without explicit written consent.
  • No persistent user profiles beyond what is needed to run an assembly.
  • No secrets or credentials stored in source code or version control.

Where this stops

  • Assembley holds no third-party security certification. Nothing here has been audited by anyone outside the company.
  • Backups are taken by hand before an assembly, not on a schedule. Automated backups depend on a paid database plan the project is not yet on.
  • Nothing is deleted on a timer. The retention periods in the Data Processing Agreement are honoured by acting on a request, not by an automatic purge.
  • Access to production is not reviewed on a schedule, and administrative access is an elevation of an ordinary account rather than a separate credential.
  • Nothing checks dependencies for known vulnerabilities on a schedule.

Reporting a vulnerability

Write to security@assembley.dk. Tell us what you found, how to reproduce it, and what you think it lets someone do. We do not publish a PGP key; if you need to send something encrypted, ask and we will arrange it.

Clause 34.3 of the Terms of Service makes testing conducted in accordance with this process an exception to the acceptable-use prohibition. Testing outside it is not covered.

What is in scope

  • assembley.dk and www.assembley.dk, including the application served from them

What is out of scope

  • Denial of service, load testing, and anything that degrades the service for others
  • Social engineering of our people, our customers, or their members
  • Physical attacks against offices or hardware
  • Third-party services we use but do not operate — report those to their owners
  • Findings that require access to another customer’s account, or credentials you were not given
  • Automated scanning at volume

Rules

  • Do not access, modify or delete data belonging to anyone else. If you reach someone else’s data by accident, stop and tell us what you did.
  • Do not remove data from the system. A screenshot of a single record is evidence; a copy of a table is not.
  • Stop at proof of concept. Demonstrating that something is possible is the finding; going further is not.
  • Do not disclose publicly until we have agreed a date with you.

What we commit to

  • We confirm we have received your report.
  • We keep you informed while we are working on it.
  • We tell you when it is resolved.
  • We agree a disclosure date with you rather than imposing one.
  • We will not pursue legal action for good-faith research conducted within these rules, and we will say so in writing if you ask.

We do not offer a bounty. We would rather say so than leave it open.

Statement of scope

Quoted from Annex II §10 of the Data Processing Agreement, which is the binding form of it. The measures on this page are described there; nothing here adds to them.

Assembley holds no third-party security certification as at the date of this DPA. The measures above are described as implemented; they are not certified by an external auditor, and Assembley makes no representation that they render Customer Personal Data secure against all forms of attack or compromise.