Securing customer export files and order data: encrypted storage vs the Downloads folder trap
Disclosure: some links in this guide are affiliate links. If you sign up through them, I may earn a commission at no extra cost to you. How this site makes money.
Every customer or order export from Shopify or WooCommerce is a spreadsheet of names, emails, addresses and phone numbers, and by default it lands in the Downloads folder, often in a cloud-synced Desktop or Documents folder, and then in an email to the accountant. Treat exports as short-lived: export only when needed, move the file into an end-to-end encrypted locker straight away, share it through an encrypted link instead of an attachment, and delete the plain copies. Full-disk encryption protects a laptop that is switched off; it doesn't protect files that sync to the cloud, get attached to email or are read by malware on a running machine. Under the GDPR, data that is encrypted and unreadable to whoever got it can spare you from notifying every affected customer after a breach. NordLocker is the simplest end-to-end encrypted option for non-technical staff; Cryptomator and GPG are free open-source alternatives. Our tested Python scanner finds exports left in plain text without printing their contents.
Store owners spend money on a WAF, two-factor login and PCI-compliant payments, then click "Export customers" and save every customer's name, email, phone number and address to Downloads/customers_export.csv. The file stays there for months. It syncs to the cloud, gets attached to an email to the accountant, and is copied to a USB stick for the person doing the newsletter. None of these copies is covered by the store's security. This guide covers where exports end up, what actually protects them, and a script that finds the ones already lying around.
NordLocker's features come from its own website, checked in October 2026; we didn't audit its encryption, and its client is closed source. GDPR references are to the regulation's text (Articles 5, 32, 33 and 34). This is practical guidance, not legal advice. The scanner was tested on our machine against a folder of synthetic Shopify- and WooCommerce-style exports (CSV, semicolon CSV, XLSX written by openpyxl, a plain email list and a 200,000-row file), non-personal files that look similar, and a GPG-encrypted copy. No real customer data was used.
1. The short answer
| Where the export sits | Who can read it | What to do instead |
|---|---|---|
| Downloads, Desktop or Documents | Anyone using the computer while you're logged in, and any malware running as you. Full-disk encryption only helps when the machine is off | Move into an encrypted locker or vault right after exporting |
| A cloud-synced folder (OneDrive, Dropbox, Google Drive) | Anyone who gets into that cloud account; the provider holds the keys | Sync only encrypted lockers or vaults |
| An email attachment | Both mailboxes, every forward, and their backups, for years | Share an encrypted link, revoke it when the job is done |
| A chat upload (Slack, Teams) | Channel members and workspace admins, until someone deletes it | Same: share a link to the encrypted file |
2. How one export becomes five copies
Exporting is easy, and nothing tells you to clean up afterwards. A typical month-end goes like this. The owner exports orders for the accountant: copy 1 in Downloads. They open it in Excel and save a filtered version to the Desktop: copy 2. On Windows with OneDrive's folder backup, or macOS with iCloud's Desktop and Documents sync, the Desktop is synced, so that's copy 3 in the cloud. Then they attach it to an email: copies 4 and 5 in the sent folder and the accountant's inbox. Large Shopify exports also arrive as an emailed download link, which keeps working for anyone who has the email.
None of this is unusual, and that's the trouble. An order export usually holds everything an attacker wants for phishing your customers: names, emails, phone numbers, addresses and what they bought. A stolen laptop, a phished email account, or an infostealer that collects documents from user folders turns that file into a breach.
3. Why full-disk encryption isn't enough
BitLocker and FileVault should be on, and they're the baseline. They protect the disk when the computer is off or locked at boot: a stolen laptop is unreadable. But when you're logged in, every file is decrypted for every program you run, including malware. And the protection ends at the disk: the copy that syncs to OneDrive, the attachment and the chat upload are outside it.
What protects the file wherever it goes is encrypting the file itself, on your computer, with a key the storage provider doesn't have. That's client-side, or end-to-end, encryption. The cloud copy, the shared link and the backup are then ciphertext; only people with the key, or the shared link and its code, can open it.
4. The encrypted workflow
- Export less. If the accountant needs revenue by month, send a report without customer columns. If the 3PL needs addresses, they should get them through the integration, not a spreadsheet.
- Move the file into the locker at once, before opening it. Opening it from the locker means Excel's temporary and autosave copies don't end up in Documents.
- Share with a link, not an attachment. A link can be revoked; an attachment lives in two mailboxes forever.
- Delete the plain copy from Downloads, empty the recycle bin, and delete the sent email if the file went out as an attachment anyway. On an SSD, overwriting a file doesn't guarantee its blocks are gone; full-disk encryption is what keeps deleted data unreadable.
- Decide how long exports live. The GDPR's storage limitation principle (Article 5(1)(e)) applies to spreadsheets as much as to databases. A rule like "exports are deleted after 30 days, the store is the source of truth" is easy to follow.
- Run the scanner weekly to catch what slipped through.
5. Finding the exports already lying around
The scanner walks Downloads, Desktop and Documents (or the folders you name) and opens CSV, TSV, TXT and XLSX files. It flags a file when its header names two or more kinds of personal data (email, phone, name, billing or shipping address, postcode and so on), or when at least 5 cells hold an email address, which catches plain mailing lists with no header. It prints the path, the row count and the column names, and never a cell value, so its output is safe to paste into a ticket. Files in a synced folder are marked SYNCED.
"""Find customer and order exports left unencrypted on a workstation: CSV, TSV and XLSX files whose header names
personal data or whose cells hold email addresses. Prints paths, row counts and column names, never cell values.
Python 3.9+, standard library only.
Usage: pii_scan.py [folder ...] [--days 7] (default: Downloads, Desktop and Documents in your home folder)
Exit code 1 if a file with personal data is older than --days, for a scheduled task or cron."""
import argparse, csv, os, re, sys, time, zipfile
EMAIL = re.compile(r'[^@\s,;"<>]+@[^@\s,;"<>]+\.[A-Za-z]{2,}')
# Header words that mark personal data in Shopify, WooCommerce and spreadsheet exports
PII = re.compile(r'e-?mail|phone|mobile|first.?name|last.?name|full.?name|billing|shipping|address|street|city|'
r'zip|post.?code|postal|birth|\bdob\b|\bvat\b|tax.?id|\biban\b|ip.?address|customer', re.I)
# A whole folder name, so 'my-onedrive-notes' doesn't count; covers 'OneDrive - Company' and 'Dropbox (Team)'
SYNCED = re.compile(r'^(onedrive( - .+)?|dropbox( \(.+\))?|google ?drive|my drive|icloud ?drive|box)$', re.I)
SAMPLE_ROWS = 2000
def scan_csv(path):
with open(path, encoding='utf-8-sig', errors='replace', newline='') as f:
head = f.read(65536)
f.seek(0)
try:
dialect = csv.Sniffer().sniff(head, ',;\t|')
except csv.Error: # one column, e.g. a plain list of emails
dialect = csv.excel
rows = csv.reader(f, dialect)
header = next(rows, [])
emails = n = 0
for n, row in enumerate(rows, 1):
if n <= SAMPLE_ROWS:
emails += any(EMAIL.search(c) for c in row)
if header and EMAIL.search(','.join(header)): # no header row: the first line is data
n, emails, header = n + 1, emails + 1, []
return header, n, emails
def scan_xlsx(path):
"""First worksheet only: header from row 1, emails counted over every string in the workbook."""
with zipfile.ZipFile(path) as z:
names = z.namelist()
shared = re.findall(r'<si>(.*?)</si>', z.read('xl/sharedStrings.xml').decode('utf-8', 'replace'), re.S) \
if 'xl/sharedStrings.xml' in names else []
shared = [''.join(re.findall(r'<t[^>]*>([^<]*)</t>', s)) for s in shared]
sheet = z.read(sorted(n for n in names if n.startswith('xl/worksheets/sheet'))[0]).decode('utf-8', 'replace')
rows = re.findall(r'<row\b[^>]*>(.*?)</row>', sheet, re.S)
header = []
for cell in re.finditer(r'<c\b([^>]*)>(.*?)</c>', rows[0] if rows else '', re.S):
v = re.search(r'<v>([^<]*)</v>', cell[2])
t = re.search(r'<t[^>]*>([^<]*)</t>', cell[2])
header.append(shared[int(v[1])] if 't="s"' in cell[1] and v else (t or v)[1] if (t or v) else '')
emails = sum(1 for s in shared if EMAIL.search(s)) + len(EMAIL.findall(''.join(re.findall(r'<t[^>]*>[^<]*</t>', sheet))))
return header, max(len(rows) - 1, 0), emails
def main():
home = os.path.expanduser('~')
ap = argparse.ArgumentParser()
ap.add_argument('folders', nargs='*', default=[os.path.join(home, d) for d in ('Downloads', 'Desktop', 'Documents')])
ap.add_argument('--days', type=float, default=7, help='flag files with personal data older than this')
a = ap.parse_args()
found, stale = [], 0
for root in a.folders:
for dirpath, dirs, files in os.walk(root):
dirs[:] = [d for d in dirs if not d.startswith('.') and d != 'node_modules']
for name in files:
ext = os.path.splitext(name)[1].lower()
if ext not in ('.csv', '.tsv', '.txt', '.xlsx'):
continue
path = os.path.join(dirpath, name)
try:
header, rows, emails = scan_xlsx(path) if ext == '.xlsx' else scan_csv(path)
except (OSError, zipfile.BadZipFile, csv.Error, KeyError, IndexError, UnicodeError):
continue
cols = [h.strip() for h in header if PII.search(h or '')]
# Personal data: two or more PII columns, or an email address in at least 5 sampled rows
if rows == 0 or (len(cols) < 2 and emails < 5):
continue
age = (time.time() - os.path.getmtime(path)) / 86400
stale += age > a.days
found.append((age > a.days, age, path, rows, cols, emails, any(SYNCED.match(p) for p in path.split(os.sep))))
for old, age, path, rows, cols, emails, synced in sorted(found, key=lambda f: -f[1]):
flags = ['OLD' if old else 'new'] + (['SYNCED'] if synced else [])
print('%-10s %5.0f days %7d rows %s' % (','.join(flags), age, rows, path))
print(' personal-data columns: %s; email addresses sampled: %d'
% (', '.join(cols[:8]) or '(no header)', emails))
print('%d file(s) with personal data, %d older than %g days' % (len(found), stale, a.days))
return 1 if stale else 0
if __name__ == '__main__':
sys.exit(main())
Run it with python pii_scan.py for your own folders, or point it at a shared drive. It exits with code 1 when a file with personal data is older than --days (7 by default), so a weekly scheduled task or cron job can alert on it. Output from the test run, with the paths shortened:
OLD 40 days 500 rows ...\Downloads\orders_export_1.csv
personal-data columns: Email, Billing Name, Billing Address1, Billing City, Billing Zip, Billing Phone; email addresses sampled: 500
OLD,SYNCED 10 days 200 rows ...\OneDrive\Desktop\wc-orders.xlsx
personal-data columns: Billing First Name, Billing Last Name, Billing Email, Billing Phone; email addresses sampled: 200
new 3 days 101 rows ...\Documents\newsletter.txt
personal-data columns: (no header); email addresses sampled: 101
new 2 days 300 rows ...\Downloads\customers_export.csv
personal-data columns: First Name, Last Name, Email, Phone, Address1, City, Zip; email addresses sampled: 300
new 1 days 200000 rows ...\Downloads\big_orders_export.csv
personal-data columns: Email, Billing Name, Billing Address1, Billing Phone; email addresses sampled: 2000
5 file(s) with personal data, 2 older than 7 days
6. Test results
| File | Expected | Result |
|---|---|---|
| Shopify-style order export, 40 days old | Flagged, OLD | Pass |
| Customer export with semicolons (Excel in many European locales) | Flagged, not marked as synced | Pass |
WooCommerce-style XLSX in OneDrive\Desktop, 10 days old | Flagged, OLD and SYNCED | Pass |
| Plain list of emails, no header | Flagged | Pass |
| 200,000-row export (13 MB) | Flagged with the exact row count | Pass; the whole scan took 0.3 s |
| Product CSV, and customer counts per country | Not flagged (one "Customers" column is not personal data) | Pass |
| GPG-encrypted copy, and a corrupt .xlsx | Not flagged; no crash | Pass |
| Scanner output | Contains no email address from any file | Pass |
| Exit code | 1 with files older than 7 days; 0 with --days 60 | Pass |
| GPG round trip (AES256, symmetric) | Decrypts to the original; no plaintext in the .gpg file | Pass |
Limits worth knowing: the scanner reads the first worksheet of an XLSX file, doesn't open old .xls files, PDFs or ZIP archives, and recognizes English column names. Add your own language's words to the PII pattern if your exports use translated headers.
7. What the GDPR says about encrypted exports
Four parts of the regulation apply directly to export files:
- Article 5(1)(f), integrity and confidentiality: personal data must be protected against unauthorized access and accidental loss. A plain spreadsheet in a synced folder is hard to defend under this principle.
- Article 32, security of processing: names encryption as one of the appropriate measures.
- Article 33: a personal data breach has to be reported to the supervisory authority within 72 hours, unless it's unlikely to result in a risk to people's rights and freedoms.
- Article 34(3)(a): you don't have to notify each affected customer if the data was protected by measures that make it unintelligible to anyone not authorized to access it, "such as encryption".
In practice: a laptop stolen with a plain customers_export.csv on the Desktop may mean emailing every customer in that file. The same laptop with the export in an encrypted locker, and a key the thief doesn't have, is a very different incident. Your data protection adviser makes the final call, but encryption is what gives them that option.
8. NordLocker for the store team
NordLocker, from the company behind NordVPN, is built for exactly this workflow: you drag a file into a locker, it's encrypted on your computer, and the encrypted copy can sync to NordLocker's cloud. According to NordLocker, it uses a zero-knowledge design, so the company can't read your files, with AES-256, xChaCha20-Poly1305 and Ed25519 as its algorithms. Files can be shared by email or link with an extra access code, and the apps cover Windows, the web and mobile.
- Why it fits a small store: nobody has to understand keys or command lines. The person who exports orders can follow "drag it into the Exports locker, share the link" without training.
- Plans: a free plan with 3 GB, enough for years of CSV exports, and paid personal plans up to 2 TB. Prices vary by region and promotion, so check the plans page.
- What you're trusting: the client is closed source, so the encryption claims can't be checked by reading the code. If that matters to you, the open-source tools below do the same job with more effort.
9. Our opinion: trade-offs
- Non-technical team, exports shared with outsiders: NordLocker. Encrypted storage and sharing in one app is what gets used. A tool that's secure but awkward ends with someone attaching the CSV to an email again.
- Already on Dropbox or Google Drive, and you want open source: Cryptomator. It creates an encrypted vault inside any synced folder and is free on desktop. Sharing means sharing the vault and its password, which is clumsier for one-off files.
- Automated exports from a server: GPG or age. If a cron job exports orders for the accountant every month, encrypt to the accountant's public key in the same job (
gpg --encrypt --recipient), so the plain file never leaves the server. - Whatever you choose: fewer exports. The safest export is the one nobody made. Most month-end needs are met by reports without customer columns.
Related: encrypted off-site backups of the store database, stopping bot attacks and carding on WooCommerce and monitoring SSL, checkout and API health.
10. Tools
Top picks
| Tool | Role | Why it fits |
|---|---|---|
| End-to-end encrypted lockers, cloud sync and sharing | Client-side encryption with a zero-knowledge design, encrypted sharing by link or email, and a 3 GB free plan that holds years of exports. Usable by staff without any security background. |
Alternatives: free and open-source tools
We don't earn anything from these links.
- Cryptomator: open-source, client-side encrypted vaults inside Dropbox, Google Drive, OneDrive or any folder.
- GnuPG: encrypt files to a recipient's public key, or with a passphrase (
gpg --symmetric --cipher-algo AES256), which we used in the test. - age: a small, modern file encryption tool with short keys; good for scripts.
- VeraCrypt: encrypted containers that mount like a drive.
- The GDPR text: Articles 5, 32, 33 and 34, quoted above.
11. Pitfalls
- Opening the export from Downloads "just to check". Excel's autosave and recent-files copies follow. Move it into the locker first.
- Relying on BitLocker or FileVault alone. They stop a thief, not an infostealer running as you, and not a synced copy.
- Synced Desktop and Documents folders. If OneDrive or iCloud backs them up, everything saved there is in the cloud too, readable by anyone who gets into that account.
- Sharing the locker password in the same email as the link. Send the code by another channel, such as a phone call or text message.
- Exports in shared team folders. Run the scanner on the shared drive too; old exports pile up where everyone assumes someone else cleans up.
- Losing the key. Zero-knowledge means the vendor can't reset access to your files. Store the master password and recovery key somewhere you'll find them.
A customer export is a breach in waiting from the moment it lands in Downloads. Export less, move each export into an end-to-end encrypted locker before you open it, share links instead of attachments, delete the plain copies, and run a weekly scan for what slipped through. NordLocker is the easiest way to make that the habit for a non-technical team; Cryptomator and GPG do the same job for free with more effort.