diff --git a/backend/app/api/passwords.py b/backend/app/api/passwords.py
index a78d48e..6530974 100644
--- a/backend/app/api/passwords.py
+++ b/backend/app/api/passwords.py
@@ -359,3 +359,156 @@ def import_keepass():
except Exception as e:
return jsonify({'error': f'Import fehlgeschlagen: {str(e)}'}), 400
+
+
+# --- Firefox CSV Import ---
+
+@api_bp.route('/passwords/import/firefox', methods=['POST'])
+@token_required
+def import_firefox():
+ """Import passwords from Firefox CSV export.
+
+ Firefox: Einstellungen > Passwoerter > ... > Passwoerter exportieren
+ CSV columns: url, username, password, httpRealm, formActionOrigin, guid, timeCreated, timeLastUsed, timePasswordChanged
+ """
+ user = request.current_user
+
+ if 'file' not in request.files:
+ return jsonify({'error': 'Keine Datei gesendet'}), 400
+
+ csv_file = request.files['file']
+
+ try:
+ import csv
+ import io
+
+ content = csv_file.read().decode('utf-8')
+ reader = csv.DictReader(io.StringIO(content))
+
+ entries = []
+ for row in reader:
+ url = row.get('url', row.get('origin', '')).strip()
+ username = row.get('username', '').strip()
+ password = row.get('password', '').strip()
+
+ if not url and not username and not password:
+ continue
+
+ # Extract domain as title
+ title = url
+ try:
+ from urllib.parse import urlparse
+ parsed = urlparse(url)
+ title = parsed.netloc or parsed.path or url
+ except Exception:
+ pass
+
+ entries.append({
+ 'title': title,
+ 'url': url,
+ 'username': username,
+ 'password': password,
+ 'notes': '',
+ 'totp': '',
+ 'group': 'Firefox Import',
+ })
+
+ return jsonify({
+ 'entries': entries,
+ 'groups': [{'name': 'Firefox Import', 'uuid': 'firefox-import', 'parent_uuid': None}] if entries else [],
+ 'count': len(entries),
+ }), 200
+
+ except Exception as e:
+ return jsonify({'error': f'CSV-Import fehlgeschlagen: {str(e)}'}), 400
+
+
+# --- Generic CSV Import (Chrome, Bitwarden, etc.) ---
+
+@api_bp.route('/passwords/import/csv', methods=['POST'])
+@token_required
+def import_generic_csv():
+ """Import passwords from generic CSV (Chrome, Bitwarden, 1Password, etc.)
+
+ Tries to auto-detect columns: name/title, url, username, password, notes
+ """
+ user = request.current_user
+
+ if 'file' not in request.files:
+ return jsonify({'error': 'Keine Datei gesendet'}), 400
+
+ csv_file = request.files['file']
+
+ try:
+ import csv
+ import io
+
+ content = csv_file.read().decode('utf-8')
+ reader = csv.DictReader(io.StringIO(content))
+
+ # Map common column names
+ col_map = {
+ 'title': ['title', 'name', 'titel', 'bezeichnung', 'entry'],
+ 'url': ['url', 'uri', 'website', 'login_uri', 'origin'],
+ 'username': ['username', 'user', 'login', 'benutzername', 'email', 'login_username'],
+ 'password': ['password', 'passwort', 'pass', 'login_password'],
+ 'notes': ['notes', 'note', 'notizen', 'comment', 'comments', 'extra'],
+ 'totp': ['totp', 'otp', 'login_totp', '2fa'],
+ 'group': ['group', 'folder', 'ordner', 'category', 'kategorie', 'type'],
+ }
+
+ def find_col(fieldnames, target):
+ for col_name in col_map.get(target, []):
+ for fn in fieldnames:
+ if fn.lower().strip() == col_name:
+ return fn
+ return None
+
+ fieldnames = reader.fieldnames or []
+ mapping = {target: find_col(fieldnames, target) for target in col_map}
+
+ entries = []
+ groups_set = set()
+ for row in reader:
+ def get(target):
+ col = mapping.get(target)
+ return row.get(col, '').strip() if col else ''
+
+ title = get('title')
+ url = get('url')
+ username = get('username')
+ password = get('password')
+
+ if not title and not url and not username and not password:
+ continue
+
+ if not title and url:
+ try:
+ from urllib.parse import urlparse
+ title = urlparse(url).netloc or url
+ except Exception:
+ title = url
+
+ group = get('group') or 'CSV Import'
+ groups_set.add(group)
+
+ entries.append({
+ 'title': title or '(Unbenannt)',
+ 'url': url,
+ 'username': username,
+ 'password': password,
+ 'notes': get('notes'),
+ 'totp': get('totp'),
+ 'group': group,
+ })
+
+ groups = [{'name': g, 'uuid': g, 'parent_uuid': None} for g in groups_set]
+
+ return jsonify({
+ 'entries': entries,
+ 'groups': groups,
+ 'count': len(entries),
+ }), 200
+
+ except Exception as e:
+ return jsonify({'error': f'CSV-Import fehlgeschlagen: {str(e)}'}), 400
diff --git a/frontend/src/views/PasswordsView.vue b/frontend/src/views/PasswordsView.vue
index 8a1ac34..3ebacdd 100644
--- a/frontend/src/views/PasswordsView.vue
+++ b/frontend/src/views/PasswordsView.vue
@@ -5,7 +5,7 @@
@@ -110,20 +110,38 @@
-
-