mozilla

Mozilla Nederland LogoDe Nederlandse
Mozilla-gemeenschap

www.netties.be - netties.be

Nieuws verzameld via Google - ma, 22/12/2025 - 18:23
www.netties.be  netties.be
Categorieën: Mozilla-nl planet

Wladimir Palant: Unpacking VStarcam firmware for fun and profit

Mozilla planet - ma, 15/12/2025 - 15:19

One important player in the PPPP protocol business is VStarcam. At the very least they’ve already accumulated an impressive portfolio of security issues. Like exposing system configuration including access password unprotected in the Web UI (discovered by multiple people independently from the look of it). Or the open telnet port accepting hardcoded credentials (definitely discovered by lots of people independently). In fact, these cameras have been seen used as part of a botnet, likely thanks to some documented vulnerabilities in their user interface.

Is that a thing of the past? Are there updates fixing these issues? Which devices can be updated? These questions are surprisingly hard to answer. I found zero information on VStarcam firmware versions, available updates or security fixes. In fact, it doesn’t look like they ever even acknowledged learning about the existence of these vulnerabilities.

No way around downloading these firmware updates and having a look for myself. With surprising results. First of all: there are lots of firmware updates. It seems that VStarcam accumulated a huge number of firmware branches. And even though not all of them even have an active or downloadable update, the number of currently available updates goes into hundreds.

And the other aspect: the variety of update formats is staggering, and often enough standard tools like binwalk aren’t too useful. It took some time figuring out how to unpack some of the more obscure variants, so I’m documenting it all here.

Warning: Lots of quick-and-dirty Python code ahead. Minimal error checking, use at your own risk!

Contents ZIP-packed incremental updates

These incremental updates don’t contain an image of the entire system, only the files that need updating. They always contain the main application however, which is what matters.

Recognizing this format is easy, the files start with the 32 bytes www.object-camera.com.by.hongzx. or www.veepai.com/design.rock-peng. (the old and the new variant respectively). The files end with the same string in reverse order. Everything in between is a sequence of ZIP files, with each file packed in its own ZIP file.

Each ZIP file is preceded by a 140 byte header: 64 byte directory name, 64 byte file name, 4 byte ZIP file size, 4 byte timestamp of some kind and 4 zero bytes. While binwalk can handle this format, having each file extracted into a separate directory structure isn’t optimal. A simple Python script can do better:

#!/usr/bin/env python3 import datetime import io import struct import os import sys import zipfile def unpack_zip_stream(input: io.BytesIO, targetdir: str) -> None: targetdir = os.path.normpath(targetdir) while True: header = input.read(0x8c) if len(header) < 0x8c: break _, _, size, _, _ = struct.unpack('<64s64sLLL', header) data = input.read(size) with zipfile.ZipFile(io.BytesIO(data)) as archive: for member in archive.infolist(): path = os.path.normpath( os.path.join(targetdir, member.filename) ) if os.path.commonprefix((path, targetdir)) != targetdir: raise Exception('Invalid target path', path) try: os.makedirs(os.path.dirname(path)) except FileExistsError: pass with archive.open(member) as member_input: data = member_input.read() with open(path, 'wb') as output: output.write(data) time = datetime.datetime(*member.date_time).timestamp() os.utime(path, (time, time)) if __name__ == '__main__': if len(sys.argv) != 3: print(f'Usage: {sys.argv[0]} in-file target-dir', file=sys.stderr) sys.exit(1) if os.path.exists(sys.argv[2]): raise Exception('Target directory exists') with open(sys.argv[1], 'rb') as input: header = input.read(32) if (header != b'www.object-camera.com.by.hongzx.' and header != b'www.veepai.com/design.rock-peng.'): raise Exception('Wrong file format') unpack_zip_stream(input, sys.argv[2]) VStarcam pack system

This format is pretty simple. There is an identical section starting with VSTARCAM_PACK_SYSTEM_HEAD and ending with VSTARCAM_PACK_SYSTEM_TAIL at the start and at the end of the file. This section seems to contain a payload size and its MD5 hash.

There are two types of payload here. One is a raw SquashFS image starting with hsqs. These seem to be updates to the base system: they contain an entire Linux root filesystem and the Web UI root but not the actual application. The matching application lives on a different partition and is likely delivered via incremental updates.

The other variant seems to be used for hardware running LiteOS rather than Linux. The payload here starts with a 16 byte header: compressed size, uncompressed size and an 8 byte identification of the compression algorithm. The latter is usually gziphead, meaning standard gzip compression. After uncompressing you get a single executable binary containing the entire operating system, drivers, and the actual application.

So far binwalk can handle all these files just fine. I found exactly one exception, firmware version 48.60.30.22. It seems to be another LiteOS-based update but the compression algorithm field is all zeroes. The actual compressed stream has some distinct features that make it look like none of the common compression algorithms.

 ff ff 0f 00 00.

Well, I had to move on here, so that’s the one update file I haven’t managed to unpack.

VeePai updates

This is a format that seems to be used by newer VStarcam hardware. At offset 8 these files contain a firmware version like www.veepai.com-10.201.120.54. Offsets of the payload vary but it is a SquashFS image, so binwalk can be used to find and unpack it.

Normally these are updates for the partition where the VStarcam application resides in. In a few cases these are updating the Linux base system however, no application-specific files from what I could tell.

Ingenic updates

This format seems to be specific to the Ingenic hardware platform, and I’ve seen other hardware vendors use it as well. One noticeable feature here is the presence of a tag partition containing various data sections, e.g. the CMDL section encoding Linux kernel parameters.

In fact, looking for that tag partition within the update might be helpful to recognize the format. While the update files usually start with the 11 22 33 44 magic bytes, they sometimes start with a different byte combination. There is always the firmware version at offset 8 in the file however.

The total size of the file header is 40 bytes. It is followed by a sequence of partitions, each preceded by a 16 byte header where bytes 1 to 4 encode the partition index and bytes 9 to 12 the partition size.

Binwalk can recognize and extract some partitions but not all of them. If you prefer having all partitions extracted you can use a simple Python script:

#!/usr/bin/env python3 import io import struct import os import sys def unpack_ingenic_update(input: io.BytesIO, targetdir: str) -> None: os.makedirs(targetdir) input.read(40) while True: header = input.read(16) if len(header) < 16: break index, _, size, _ = struct.unpack('<LLLL', header) data = input.read(size) if len(data) < size: raise Exception(f'Unexpected end of data') path = os.path.join(targetdir, f'mtdblock{index}') with open(path, 'wb') as output: output.write(data) if __name__ == '__main__': if len(sys.argv) != 3: print(f'Usage: {sys.argv[0]} in-file target-dir', file=sys.stderr) sys.exit(1) with open(sys.argv[1], 'rb') as input: unpack_ingenic_update(input, sys.argv[2])

You will find some partitions rather tricky to unpack however.

LZO-compressed partitions

Some partitions contain a file name at offset 34, typically rootfs_camera.cpio. These are LZO-compressed but lack the usual magic bytes. Instead, the first four bytes contain the size of compressed data in this partition. Once you replace these four bytes by 89 4c 5a 4f (removing trailing junk is optional) the partition can be uncompressed with the regular lzop tool and the result fed into cpio to get the individual files.

Ingenic’s jzlzma compression

Other Ingenic root partitions are more tricky. These also start with the data size but it is followed by the bytes 56 19 05 27 (that’s a uImage signature in reversed byte order). After that comes a compressed stream that sort of looks like LZMA but isn’t LZMA. What’s more: while binwalk will report that the Linux kernel is compressed via LZ4, it’s actually the same strange compression mechanism. The bootloader of these systems pre-dates the introduction of LZ4, so the same compression algorithm identifier was used for this compression mechanism that was later assigned to LZ4 by the upstream version of the bootloader.

What kind of compression is this? I’ve spent some time analyzing the bootloader but it turned out to be a red herring: apparently, the decompression is performed by hardware here, and the bootloader merely pushes the data into designated memory areas. Ugh!

At least the bootloader told me how it is called: jzlzma, which is apparently Ingenic’s proprietary LZMA variant. An LZMA header starts with a byte encoding some compression properties (typically 5D), a 4 byte dictionary size and an 8 byte uncompressed size. Ingenic’s header is missing compression properties, and the uncompressed size is merely 4 bytes. But even accounting for these differences the stream cannot be decompressed with a regular LZMA decoder.

Luckily, with the algorithm name I found tools on Github that are meant to create firmware images for the Ingenic platform. These included an lzma binary which turned out to be an actual LZMA tool from 2005 hacked up to produce a second compressed stream in Ingenic’s proprietary format.

As I found, Ingenic’s format has essentially two differences to regular LZMA:

  1. Bit order: Ingenic encodes bits within bytes in reverse order. Also, some of the numbers (not all of them) are written to the bit stream in reversed bit order.
  2. Range coding: Ingenic doesn’t do any range coding, instead encoding all numbers verbatim.

That second difference essentially turns LZMA into LZ77. Clearly, the issue here was the complexity of implementing probabilistic range coding in hardware. Of course, that change makes the resulting algorithm produce considerably worse compression ratios than LZMA and even worse than much simpler LZ77-derived algorithms like deflate. And there is plenty of hardware to do deflate decompression. But at least they managed to obfuscate the data…

My original thought was “fixing” their stream and turning it into proper LZMA. But range coding is not only complex but also context-dependent, it cannot be done without decompressing. So I ended up just writing the decompression logic in Python which luckily was much simpler than doing the same thing for LZMA proper.

Note: The following script is minimalistic and wasn’t built for performance. Also, it expects a file that starts with a dictionary size (typically the bytes 00 00 01 00), so if you have some header preceding it you need to remove it first. It will also happily “uncompress” any trailing junk you might have there.

#!/usr/bin/env python3 import sys kStartPosModelIndex, kEndPosModelIndex, kNumAlignBits = 4, 14, 4 def reverse_bits(n, bits): reversed = 0 for i in range(bits): reversed <<= 1 if n & (1 << i): reversed |= 1 return reversed def bit_stream(data): for byte in data: for bit in range(8): yield 1 if byte & (1 << bit) else 0 def read_num(stream, bits): num = 0 for _ in range(bits): num = (num << 1) | next(stream) return num def decode_length(stream): if next(stream) == 0: return read_num(stream, 3) + 2 elif next(stream) == 0: return read_num(stream, 3) + 10 else: return read_num(stream, 8) + 18 def decode_dist(stream): posSlot = read_num(stream, 6) if posSlot < kStartPosModelIndex: pos = posSlot else: numDirectBits = (posSlot >> 1) - 1 pos = (2 | (posSlot & 1)) << numDirectBits if posSlot < kEndPosModelIndex: pos += reverse_bits(read_num(stream, numDirectBits), numDirectBits) else: pos += read_num(stream, numDirectBits - kNumAlignBits) << kNumAlignBits pos += reverse_bits(read_num(stream, kNumAlignBits), kNumAlignBits) return pos def jzlzma_decompress(data): stream = bit_stream(data) reps = [0, 0, 0, 0] decompressed = [] try: while True: if next(stream) == 0: # LIT byte = read_num(stream, 8) decompressed.append(byte) else: size = 0 if next(stream) == 0: # MATCH size = decode_length(stream) reps.insert(0, decode_dist(stream)) reps.pop() elif next(stream) == 0: if next(stream) == 0: # SHORTREP size = 1 else: # LONGREP[0] pass elif next(stream) == 0: # LONGREP[1] reps.insert(0, reps.pop(1)) elif next(stream) == 0: # LONGREP[2] reps.insert(0, reps.pop(2)) else: # LONGREP[3] reps.insert(0, reps.pop(3)) if size == 0: size = decode_length(stream) curLen = len(decompressed) start = curLen - reps[0] - 1 while size > 0: end = min(start + size, curLen) decompressed.extend(decompressed[start:end]) size -= end - start except StopIteration: return bytes(decompressed) if __name__ == '__main__': if len(sys.argv) != 3: print(f'Usage: {sys.argv[0]} in-file.jzlzma out-file', file=sys.stderr) sys.exit(1) with open(sys.argv[1], 'rb') as input: data = input.read() data = jzlzma_decompress(data[8:]) with open(sys.argv[2], 'wb') as output: output.write(data)

The uncompressed root partition can be fed into the regular cpio tool to get the individual files.

Exotic Ingenic update

There was one update using a completely different format despite also being meant for the Ingenic hardware. This one started with the bytes a5 ef fe 5a and had a SquashFS image at offset 0x3000. The unpacked contents (binwalk will do) don’t look like any of the other updates either: this definitely isn’t a camera, and it doesn’t have a PPPP implementation. Given the HDMI code I can only guess that this is a Network Video Recorder (NVR).

But what about these security issues?

As to those security issues I am glad to report that VStarcam solved the telnet issue:

export PATH=/system/system/bin:$PATH #telnetd export LD_LIBRARY_PATH=/system/system/lib:/mnt/lib:$LD_LIBRARY_PATH mount -t tmpfs none /tmp -o size=3m /system/system/bin/brushFlash /system/system/bin/updata /system/system/bin/wifidaemon & /system/system/bin/upgrade &

Yes, their startup script really has telnetd call commented out. At least that’s usually the case. There are updates from 2018 that are no longer opening the telnet port. There are other updates from 2025 that still do. Don’t ask me why. From what I can tell the hardcoded administrator credentials are still universally present but these are only problematic with the latter group.

It’s a similar story with the system.ini file that was accessible without authentication. Some firmware versions had this file moved to a different directory, others still have it in the web root. There is no real system behind it, and I even doubt that this was a security-induced change rather than an adjustment to a different hardware platform.

Categorieën: Mozilla-nl planet

Tarek Ziadé: All I Want for Christmas is a Better Alt Text – Part 1

Mozilla planet - ma, 15/12/2025 - 01:00
Context: Improving Alt Text for Firefox

Earlier this year, I built the backend for the local alt text generation feature in Firefox. Nearly half of the images on the web still lack alternative text, creating a major accessibility barrier for screen reader users. The goal of this work is straightforward but ambitious: generate high-quality alt text entirely on device, preserving user privacy while improving access to visual content.

The first implementation focused on PDF.js, primarily as a controlled environment to validate the approach. Now that the runtime performance is good enough, the next step is to generalize this capability across the entire browser so that all web images can benefit from meaningful descriptions. Before that generalization, however, improving accuracy is essential.

From a modeling perspective, the system pairs a Vision Transformer (ViT) with DistilGPT-2, a 182-million-parameter language model that fits under 200 MB once quantized. Improving this system involves multiple, often competing dimensions: bias reduction, description accuracy, and inference speed. This post focuses on the data side of the problem, specifically dataset quality and bias. Part 2 will look at model-level improvements for accuracy and performance.

First Round: Removing Bias with GPT-4o

The original image captions contained several recurring issues:

  • Gender bias: skateboarders described as “men”, nurses as “women”
  • Age stereotyping: unnecessary or reductive age descriptors
  • Offensive or outdated language: culturally insensitive terms that no longer belong in a modern dataset

To address this, I used GPT-4o to systematically transform captions from Flickr30k and COCO, removing demographic descriptors that were not visually required. The resulting datasets are available on Hugging Face (Mozilla/flickr30k-transformed-captions-gpt4o) and were used to train the current Firefox local alt text model.

For more background on this initial effort, see the Mozilla Hacks post and the Firefox blog announcement. This is the model that is currently shipping in Firefox.

Second Round: Measuring What Actually Improved

Qualitative panel testing showed that the transformed captions were generally better received by humans, but that only answered part of the question. What exactly improved, by how much, and what problems remained hidden in the data?

This post documents the second round of work, which focused on building systematic measurement tools to:

  1. Quantify how much bias was actually removed
  2. Verify that transformed captions still describe the images accurately
  3. Identify class imbalance and other structural issues
  4. Lay the groundwork for targeted fixes, including synthetic data generation

When training vision-language models, dataset quality is often treated as a secondary concern compared to architecture or training tricks. In practice, the data is the foundation. If the dataset is biased, noisy, or unbalanced, no amount of fine-tuning will fully compensate.

The Problem Space

After the GPT-4o transformation, several open questions remained:

  • Did bias removal actually work in a measurable way?
  • Was semantic meaning preserved during transformation?
  • Did image–text alignment degrade or improve?
  • Are some visual concepts severely underrepresented?
  • Can these checks be repeated reliably for future dataset versions?

Answering these questions requires more than a single score or benchmark.

A Multi-Metric Quality Analysis

I built a dataset quality analysis tool that evaluates four complementary dimensions. The emphasis is on improving the training data itself, rather than compensating for data issues at model time.

1. Image–Text Alignment (CLIP Score)

CLIP provides a convenient proxy for how well a caption matches its corresponding image. By embedding both modalities and computing cosine similarity, I obtain a rough but useful alignment score.

A key improvement in this round was upgrading from CLIP ViT-B/32 to ViT-L/14 @ 336 px. The larger model produces lower absolute scores, but it is significantly more discriminative, making it easier to separate strong alignments from weak ones.

Interpretation guidelines:

  • Excellent: ≥ 0.35
  • Good: 0.30–0.35
  • Fair: 0.25–0.30
  • Poor: < 0.25

On the transformed dataset, I observe scores of 0.311 with ViT-B/32 (Good) and 0.284 with ViT-L/14 @ 336 px (Fair but more informative).

2. Caption Fidelity (BERTScore)

Removing bias should not come at the cost of semantic drift. To verify this, I used BERTScore with a RoBERTa-large backbone to compare original and transformed captions.

Scores above 0.90 generally indicate that the core meaning is preserved. The transformed dataset achieves 0.904, which falls comfortably in the “excellent” range.

3. Bias Detection Before and After

Bias reduction is only meaningful if it can be measured. I tracked mentions of protected attributes across seven categories, including gender, race or ethnicity, nationality, age, religion, sexual orientation, and disability.

By comparing original and transformed captions on the same samples, I can directly quantify the effect of the transformation. On a 1 000-sample evaluation set, gender mentions dropped from 70 percent to zero, race and ethnicity mentions dropped by 97 percent, and nationality mentions were completely eliminated. Age-related terms remain more common, largely because they are often visually relevant, for example when describing children.

4. Object Distribution and Imbalance

Finally, I analyzed object frequency to identify long-tail problems. Using metrics such as the Gini coefficient and Shannon entropy, the tool highlights severe imbalance: thousands of objects appear only a handful of times.

This analysis automatically produces lists of rare objects and sampling weights that can be used for rebalancing during training.

Using CLIP as a Training Signal

Beyond evaluation, CLIP can also be used to guide training directly. I experimented with a combined loss that adds a CLIP-based alignment term to the standard cross-entropy loss for caption generation.

The intuition is simple: encourage the model to generate captions that are not only fluent, but also visually grounded. Early results suggest modest but consistent gains in CLIP score, at the cost of slower training and higher memory usage.

Running the Quality Analysis

The quality analysis tool integrates directly into the project’s Makefile:

# Quick test (100 samples) make quality-report-quick # Full analysis on test split make quality-report SPLIT=test # Custom analysis make quality-report SPLIT=train MAX_SAMPLES=1000 OUTPUT_DIR=./my_reports Example Dataset Quality Report

Below is an excerpt from the generated quality report for the full Flickr30k transformed dataset. It illustrates how the metrics come together in practice.

================================================================================ DATASET QUALITY REPORT ================================================================================ Dataset: Mozilla/flickr30k-transformed-captions-gpt4o Samples: 31 014 IMAGE–TEXT ALIGNMENT (CLIP) Score: 0.274 ± 0.036 Assessment: FAIR CAPTION FIDELITY (BERTScore) Score: 0.899 ± 0.023 Assessment: GOOD BIAS DETECTION (Original → Transformed) Gender: 67% → 0% Race/Ethnicity: 27% → 1% Nationality: 1% → 0% Age: 19% → 17% OBJECT DISTRIBUTION Gini coefficient: 0.889 Rare classes (<50 samples): 6 210 ================================================================================

The report confirms that the GPT-4o transformation is highly effective at removing demographic bias while preserving meaning. At the same time, it surfaces two remaining issues: only fair image–text alignment and severe class imbalance.

Output Files

The analysis produces the following artifacts:

Directory: quality_reports/ • summary.json - Aggregate metrics in JSON format • quality_report.txt - Human-readable summary report • per_example_scores.csv - Per-sample CLIP, BERT, and bias scores • ranked_by_combined.csv - Samples ranked by combined quality score • object_counts.csv - Object frequency distribution • objects_below_50.csv - Rare / underrepresented objects (≤50 samples) • reweighting_probs.csv - Sampling probabilities for balanced training • lorenz_curve.png - Object distribution inequality visualization • top_failures/ - Top failure cases with images and captions

These artifacts make it easy to audit dataset quality, compare runs, and target specific weaknesses.

Key Takeaways
  • Dataset quality cannot be captured by a single metric
  • Bias removal can be measured and verified quantitatively
  • Larger CLIP models are more useful for discrimination, even if absolute scores are lower
  • Alignment-aware training objectives show promise
  • Class imbalance remains a major, and solvable, issue
What Comes Next

None of these improvements are shipping yet. They are preparatory steps that make future work safer and more predictable. With solid metrics in place, the next phase is to train improved models, validate gains rigorously, and continue reducing long-tail failures.

The long-term goal remains unchanged: provide high-quality, privacy-preserving alt text for the large fraction of web images that still lack it, and do so in a way that is fair, transparent, and measurable.

References and Resources Background Datasets Metrics Code
Categorieën: Mozilla-nl planet

The Servo Blog: November in Servo: monthly releases, context menus, parallel CSS parsing, and more!

Mozilla planet - ma, 15/12/2025 - 01:00

Correction (2026-01-19)

An earlier version of this post said that Servo now has full support for ChaCha20-Poly1305, but this was incorrect. We had only landed the ‘importKey’ and ‘exportKey’ operations. The ‘encrypt’, ‘decrypt’, and ‘generateKey’ options landed in the following month.

Landing in Servo 0.0.3 and our November nightly builds, we now have context menus for links, images, and other web content (@atbrakhi, @mrobinson, #40434, #40501), vsync on Android (@mrobinson, #40306), light mode for the new tab page (@arihant2math, #40272), plus several web platform features:

Servo 0.0.3 showing new support for <use> in SVG, <details name>, and context menus

Font variations are now applied in ‘font-weight’ and ‘font-stretch’ (@simonwuelker, #40867), fixing a rendering issue in the Web Engines Hackfest website.

@kkoyung has landed some huge improvements in the SubtleCrypto API, including some of the more modern algorithms in this WICG draft, and a fix for constant-time base64 (@kkoyung, #40334). We now have full support for SHA3-256, SHA3-384, SHA3-512 (@kkoyung, #40765), cSHAKE128, cSHAKE256 (@kkoyung, #40832), Argon2d, Argon2i, Argon2id, ChaCha20-Poly1305, ECDH, ECDSA, and X25519:

Algorithm deriveBits exportKey generateKey importKey sign verify Argon2d #40936 n/a n/a #40932 n/a n/a Argon2i #40936 n/a n/a #40932 n/a n/a Argon2id #40936 n/a n/a #40932 n/a n/a ChaCha20-Poly1305 n/a #40948 n/a #40948 n/a n/a ECDH #40333 #40298 #40305 #40253 n/a n/a ECDSA n/a #40536 #40553 #40523 #40591 #40557 X25519 #40497 #40421 #40480 #40398 n/a n/a

<details> now fires ‘toggle’ events (@lukewarlow, #40271), and <details name> is now exclusive, like radio buttons (@simonwuelker, #40314). InputEvent, which represents ‘input’ and ‘beforeinput’ events, now has composed, data, isComposing, and inputType properties (@excitablesnowball, #39989).

Embedding API

Each webview can now now have its own rendering context (@mrobinson, @mukilan, #40794, #40738, #40721, #40594, #40923). This effectively enables full support for multiple windows, and we’ve started incorporating that into servoshell (@mrobinson, @mukilan, #40883).

Our previously unused context menu API has been replaced with a new, more effective API that includes actions for links, images, and other web content (@mrobinson, @atbrakhi, #40402, #40501, #40607). For more details, see the docs for ContextMenu, EmbedderControl::ContextMenu, and WebViewDelegate::show_embedder_control().

WebView now has can_go_back() and can_go_forward() methods, and servoshell now uses those to disable the back and forward buttons (@mrobinson, #40598).

Having introduced our new RefreshDriver API in October, we’ve now removed Servo::animating() (@mrobinson, #40799) and ServoDelegate::notify_animating_changed() (@mrobinson, #40886), and similarly cleaned up the obsolete and inefficient “animating” state in servoshell (@mrobinson, #40715).

We’ve moved virtually all of the useful items in the Servo API to the root of the servo library crate (@mrobinson, #40951). This is a breaking change, but we expect that it will greatly simplify embedding Servo, and it means you can even write use servo::*; in a pinch.

When running Servo without a custom ClipboardDelegate, we normally use the system clipboard by default. But if there’s no system clipboard, we now have a built-in fallback clipboard (@mrobinson, #40408), rather than having no clipboard at all. Note that the fallback clipboard is very limited, as it can only store text and does not work across processes.

Performance and stability

Servo now parses CSS in parallel with script and layout (@mrobinson, @vimpunk, #40639, #40556), and can now measure Largest Contentful Paint in PerformanceObserver as well as in our internal profiling tools (@shubhamg13, @boluochoufeng, #39714, #39384).

Just-in-time compilation (JIT) is now optional (@jschwe, #37972), which can be useful in situations where generating native code is forbidden by policy or unwanted for other reasons.

We’ve improved the performance of incremental layout (@Loirooriol, @mrobinson, #40795, #40797), touch input (@kongbai1996, #40637), animated GIF rendering (@mrobinson, #40158), the prefs subsystem (@webbeef, #40775), and parseFromString() on DOMParser (@webbeef, #40742). We also use fewer IPC resources when internal profiling features are disabled (@lumiscosity, #40823).

We’ve fixed a bug causing nytimes.com to hang (@jdm, #40811), as well as fixing crashes in Speedometer 3.0 and 3.1 (@Narfinger, #40459), grid layout (@nicoburns, #40821), the fonts subsystem (@simonwuelker, #40913), XPath (@simonwuelker, #40411), ReadableStream (@Taym95, #40911), AudioContext (@Taym95, #40729), and when exiting Servo (@mrobinson, #40933).

Donations

Thanks again for your generous support! We are now receiving 6433 USD/month (+11.8% over October) in recurring donations. This helps us cover the cost of our speedy CI and benchmarking servers, one of our latest Outreachy interns, and funding maintainer work that helps more people contribute to Servo.

Servo is also on thanks.dev, and already 28 GitHub users (same as October) that depend on Servo are sponsoring us there. If you use Servo libraries like url, html5ever, selectors, or cssparser, signing up for thanks.dev could be a good way for you (or your employer) to give back to the community.

We now have sponsorship tiers that allow you or your organisation to donate to the Servo project with public acknowlegement of your support. A big thanks from Servo to our newest Bronze Sponsors: Jenny & Phil Porada, Josh Aas, LambdaTest, and Sandwich! If you’re interested in this kind of sponsorship, please contact us at join@servo.org.

6433 USD/month 10000

Use of donations is decided transparently via the Technical Steering Committee’s public funding request process, and active proposals are tracked in servo/project#187. For more details, head to our Sponsorship page.

Categorieën: Mozilla-nl planet

Thunderbird Blog: VIDEO: Exchange Email Support

Mozilla planet - do, 11/12/2025 - 19:16

Welcome to the last Community Office Hours of 2025! In this edition, Heather and Monica welcome Sr. Software Engineer Brendan Abolivier and Software Engineer Eleanor Dicharry from the Desktop Team. We’re discussing the recent Exchange Web Services Support for email that just landed in Thunderbird Monthly Release 145. Learn how the team landed this feature and discover future plans for Calendar and Contact support, as well as Graph API, in the blog, video, and podcast below.

Community Office Hours will be back in 2026. Thank you so much for joining us for these sneak peeks into how we make, improve, and expand Thunderbird! As always, if you have any ideas for future office hours topics, let us know in the comments!

What is Exchange and why did this take so long?

Exchange is the server-side product that hosts Microsoft’s e-mail, address book, and calendar services. Exchange powers both Microsoft services in the cloud on Microsoft 365 as well as on premises servers run by organizations. 

This is the first protocol we’ve added in over 20 years. We have an older code base that was in survival mode for a long time, and knowing the code well enough to improve on it is a challenge. So we had to understand how everything fit together first. The good news is this entire process will make adding future protocols, like JMAP and Graph, which will ultimately replace Exchange, go much faster.

Signing into Exchange in Thunderbird 145

Right now, only mail is supported. When users add an account, Thunderbird will try to detect if EWS (Exchange Web Services, the API we currently use to interact with Exchange servers) is available. Users can use this in the new Account Hub and in manual account configuration for Microsoft Exchange-hosted accounts. Like IMAP and other server types, users can set which folders are used for trash, spam, sent mail, and other special folders. However, the Exchange API doesn’t store this customization on the server. So these preferences will only apply actions like “move to trash
And “mark as junk” in Thunderbird. 

These limits, thankfully, only apply to folder settings themselves. The server synchronizes all folders and their messages so other clients have up-to-date views of mailboxes managed in Thunderbird.

We’re working on making EWS authentication as complete as possible, and are working with users who are helping us test less usual custom configurations. We have support for on-premises servers (aka ones your organization hosts instead of Microsoft hosting it) not using OAuth2, but this is a goal we’re working towards, along with supporting NTLM. If you have an unusual hosting or authentication option, please check out our Wiki article and get in touch to help us test.

Exchange features

Attachments: Downloading and displaying special and inline attachments should be supported. The team has especially made sure Thunderbird supports detaching and deleting attachments as well. If something doesn’t work, please report it on Bugzilla! 

Message storage: Messages come in two pieces: headers and bodies. It connects and goes through folders in order and pulls down headers, which are easy to download. There is a longer loading process to download message bodies. We’re working on adding folder subscriptions for more control of this process. We do have an option in folders to deselect individual folders from offline storage.

Sync: We made sure messages and folders are kept in sync with the server, so users can move between Thunderbird, other mail clients, and the webview. However, Thunderbird only syncs with the server on a configurable time interval after startup, which is set by default to 10 minutes. You can always use the ‘check new messages’ setting to force an instant sync.

Folder operations: Thunderbird supports all normal folder operations with EWS, except for sharing folders. This is difficult to replicate without a Microsoft-supported API we can use to do this at present. 

Filters: Filters should mostly work, though there are some limits. If you try filtering on a non-standard header isn’t supported, as we sync on a limited set of metadata. While Thunderbird 145 doesn’t support  message body filters, this is in very active development and will be improved in either 146 or 147. Another limit involves interactions between filters and notifications. You will still get notifications if a filter activates for a folder you have set not to notify you. Addressing these limitations is a current area of active development.

Search: Search for EWS accounts will function the same as it does for non-EWS accounts in Thunderbird with Message Search, Advanced Search or Quick Filters. You’ll want to start searches after your messages have downloaded, since search operates locally.

Report Bugs, Make Suggestions, and Help Test

As with everything else in Thunderbird, bug reports, suggestions, and user testing help make things even better. As stated above, if you have a non-standard hosting or authentication option, please join us on Matrix in either the Thunderbird Community Desktop Support or the Thunderbird Desktop Developers channel to learn how to join the testing effort. Test with Daily, if you feel comfortable about using it or Beta, though even testing in Release helps!

If you encounter a bug with an Exchange account, please report it on Bugzilla using the ‘Networking: Exchange’ component of the ‘MailNews: Core’ product. Have a feature you’d like to see? Suggest it at Mozilla Connect.

What about Mobile, Microsoft Graph, or Calendar and Contacts?

While the work the team has done to bring Exchange won’t directly transfer to the Android and iOS apps, it nonetheless gives us an increased familiarity with the protocol. This experience will help us bring Exchange and eventually Graph API to the mobile clients. Speaking of Microsoft Graph, this is our next priority for development. Microsoft is discontinuing support for EWS on Exchange Online accounts next October. Thankfully, work to add Microsoft Graph should go much faster, thanks to the foundational efforts with Exchange. 

This does mean that the team will need to delay their work on adding Calendar and Contacts to email support until Graph is done. Stay tuned to the Thunderbird blog for our monthly development updates and any special reports. 

VIDEO (Also on Peertube): Resources:

Exchange Mozilla Support Article: https://support.mozilla.org/en-US/kb/thunderbird-and-exchange

Exchange Mozilla Wiki Post (with call for testing): https://wiki.mozilla.org/Thunderbird%3AExchange

Reach out on Matrix: https://matrix.to/#/#thunderbird:mozilla.org 

Bugzilla (use Exchange component for reporting): https://bugzilla.mozilla.org/enter_bug.cgi?product=MailNews%20Core

The post VIDEO: Exchange Email Support appeared first on The Thunderbird Blog.

Categorieën: Mozilla-nl planet

The Mozilla Blog: What we learned about choice and control online this year

Mozilla planet - do, 11/12/2025 - 15:21

Earlier this year, we invited you to join us in celebrating online choice, and to take a stand for independence and control in your digital life. It’s a call to action at the heart of our campaign Open What You Want, which celebrates autonomy, defiance, and showing up online exactly as you are, starting with the simple act of choosing your browser. It’s one of the most important digital decisions you can make, shaping how you experience the web, protect your data, and express yourself online.

We wanted to understand how people think about choice in their everyday lives, how they express it, celebrate it, and fight for it. So we took Firefox on the road to connect with our communities IRL to learn more.

From coffee raves to cosplay: What we learned about choice IRL

We showed up in places where choice is part of the experience — in cities and cultural hubs where creativity, fandom, and freedom of expression thrive. From the Heroes Festival in Freiburg and our House Blend day-rave series in Chicago, Berlin, LA, and Munich, to TwitchCon in San Diego, our Footbrawl tournament in Berlin, and Comic Con in Stuttgart.

Everywhere we went, one thing was clear: people love having real choice in the moments that matter to them — whether it’s picking the coffee blend that powers their day, choosing their cosplay or gaming character, or deciding how they show up online. 

But online, choice and control have slipped from our hands, and often, when it feels like we’re choosing, Big Tech platforms have already decided for us.

Three Firefox event scenes showing a card-game booth, a pink pop browser baddie photo frame, and a drink stand serving colorful beverages.Image credits (left to right): Mondo Robot, Holger Talinski & The Barkers The reality of online choice today

To unpack this problem, we polled 8,000 adults over 18 years old in France, Germany, the UK and the U.S. on how they navigate choice and control both online and offline.  

The survey, conducted by research agency YouGov, showcases a tension between people’s desire to have control over their data and digital privacy, and the reality of the internet today — a reality defined by Big Tech platforms that make it difficult for people to exercise meaningful choice online:

  • Only 16% feel in control of their privacy choices (highest in Germany at 21%)
  • 24% feel it’s “too late” because Big Tech already has too much control or knows too much about them. And 36% said the feeling of Big Tech companies knowing too much about them is frustrating — highest among respondents in the U.S. (43%) and the UK (40%)
  • Practices respondents said frustrated them were Big Tech using their data to train AI without their permission (38%) and tracking their data without asking (47%; highest in U.S. – 55% and lowest in France – 39%) 

And from our existing research on browser choice, we know more about how defaults that are hard to change and confusing settings can bury alternatives, limiting people’s ability to choose for themselves — the real problem that fuels these dynamics.

Bar chart comparing US, UK, Germany, and France respondents’ top frustrations with Big Tech, including data tracking, targeted content, AI training, and privacy concern.

Taken together our new and existing insights could also explain why, when asked which actions feel like the strongest expressions of their independence online, choosing not to share their data (44%) was among the top three responses in each country (46% in the UK; 45% in the U.S.; 44% in France; 39% in Germany).

“At the heart of it, this study showcases why technology should serve humanity first and product design must be built with user agency, choice, and trust at the center,” says Ajit Varma, Product Vice President at Firefox. “When companies embrace this path, they can empower users and cultivate healthy competition that ultimately leads to better products for everyone.” 

We also see a powerful signal in how people think about choosing the communities and platforms they join — for 29% of respondents, this was one of their top three expressions of independence online.

“The kind of web communities thrive in — open, curious and shaped by its users — is increasingly at odds with the one Big Tech and the billionaires behind it are building. Powerful platforms today try to lock us into ecosystems and decide the products we use online,” says Christina Lang, VP of Global Marketing. “For Firefox, community has always been at the heart of what we do, and we’ll keep fighting to put real choice and control back in people’s hands so the web once again feels like it belongs to the communities that shape it.

And with Open What You Want, we set out to deliver an important message through a series of fun, unconventional experiences: choosing your browser is one of the most important digital decisions you can make.”

For more insights about local country findings from the survey, check our France, Germany, UK and U.S. (including U.S. findings deck) press releases.

Take control of your internet Download Firefox

The post What we learned about choice and control online this year appeared first on The Mozilla Blog.

Categorieën: Mozilla-nl planet

Martin Thompson: The Hacklore Letter and Privacy

Mozilla planet - do, 11/12/2025 - 01:00

Before I start, go and read https://www.hacklore.org/letter.

When it comes to endpoint security, unless you are operating in the “Mossad” threat model[1], this is solid advice. The letter is absolutely right that the advice we used to give people about operational security practices has not aged well.

However, completely rejecting some of the defunct advice might come with privacy costs.

The letter’s authors seem to have given up on online privacy, which disappoints me greatly. Privacy nihilism isn’t really a healthy attitude and it has tainted the advice.

The Good Parts

Let’s discharge the obviously good stuff. Items 1 (Avoid public WiFi), 3 (Never charge devices from public USB ports), 4 (Turn off Bluetooth and NFC), and 6 (Regularly change passwords) are all very bad advice today.

The only reservations I have are minor. The advice on USB devices is true for phones and devices on the smarter end (watches, tablets, e-readers, etc…), where this is true. Less so for peripherals and other USB whatsits[2].

The updated advice on security practices is also pretty good. Updates, multi-factor authentication, and password managers are the best security advice you can give people today[3].

Privacy Nihilism

Unfortunately, privacy is a different story. We exist in a world where – if they could – many companies would collect and analyze everything you do.

In terms of the letter, item 5 (Regularly “clear cookies”) is basically pure nihilism. The implication is that you can be tracked no matter what you do.

I don’t subscribe to that perspective. Fingerprinting is pretty effective, but not as good as this implies. Not everyone is uniquely identifiable through their fingerprint. Also, browsers are making meaningful progress at making fingerprints less useful for many people.

You do have to stop giving websites your email and phone number though. It’s absolutely true that sites are using that. Use temporary email addresses when you can[4].

That said, I don’t clear cookies. The resulting inconvenience is just not worth it. There is absolutely no security advantage from purging cookies. Instead, I recommend targeted use of private browsing modes, profiles, or containers.

Scanning QR Codes is Following a Link

Item 2 in the letter is “Never scan QR codes”. The claim is that this is bad advice.

Security-wise, this is mostly true. Sticker attacks[5] are probably the main reason that the security situation is not perfect. But that’s because of a more general phishing problem[6].

From a pure security perspective, the letter is absolutely correct. Opening any link in a browser is so overwhelmingly likely to be fine that it’s not worth worrying about. You won’t get pwned by even the most malicious link.

Browser security has gotten pretty good lately. Browsers aren’t 100% there, but you should not worry about the gap unless you are someone who operates in that “Mossad” threat model.

It’s also a bit worse if an app – rather than your browser – handles the link[7]. Either way, the risks to security are pretty remote. I don’t worry about getting poisoned by the food I buy at the supermarket; in the same way, you should not worry about following links.

The phishing problem is that you really need to trust whatever provides you with a link if you are going to enter information at the other end[6:1]. Otherwise, they could send you to some place that will steal your information[8]. That is the case though, no matter where you find the link.

Scanning QR Codes is Not Great for Privacy

Privacy-wise, QR codes are not as straightforward as this makes out. If you care about privacy, sadly the old advice holds some wisdom.

The privacy risk for QR codes is related to navigation tracking. If scanning a QR code is just following a link, following links in any context comes with a privacy cost[9].

There are small differences between links in QR codes, email[10], or on ordinary websites, but there’s one common factor: the site that you go to can learn everything about the place you found the link[11] and add that to your profile.

Every time you follow a link you are adding to the information that the destination website (or app) has about your activities.

QR codes are generally only placed in one physical location, so visiting the site almost always means that you are at that location.

That is, unlike links you find online, following a QR code can take information about where you are physically located and adds that to tracking databases.

Take the QR codes that restaurants use for menus and ordering. Many restaurants outsource all the online stuff to external services. This is fair, restaurants would probably much rather focus on making and selling food, which is more than difficult enough.

Outsourcing means that there’s a good chance that you will end up on the same site as you visit different restaurants. That website now has a log of the places you visited, including details of when you visited, what you ate, the size of the bill, and whatever else the restaurant shares with them about you. You can almost guarantee that the information they collect is for sale, unless the terms and conditions promise otherwise[13].

Avoiding QR Code Tracking

So if you would rather not help people build profiles about you every time you scan a QR code, what can you do?

Personally, I only open QR codes in a private browsing window. That way, at least the tracking sites can’t use cookies to connect your QR code into a single profile. They just get isolated visits from what might be different people.

To help with that, you can maybe set your default browser to one that doesn’t keep cookies, like Firefox Focus, DuckDuckGo’s Browser, or any browser that you set up to not keep cookies.

Products could be better in this regard. As far as I’m aware, you can’t set a different browser for QR codes on most devices[14]. For my sins, I use an iPhone[15]. Firefox iOS used to have a QR code scanning button, which made it easy to switch to private browsing and open those links in a cookie- and tracking-free tab. A recent change made scanning QR codes much more annoying[16], so I’m still looking for a better option there.

In the end, it’s easy to see why the authors of the letter have adopted a nihilistic attitude toward privacy. Personally, I don’t accept that outcome, even if it means a little more work on my part.

  1. If you are, you know already. ↩︎

  2. Those devices can be vulnerable in ways your phone isn’t. Some will allow firmware to be updated by anything they attach to. That means they will become a risk to any machine that they are subsequently plugged in to. ↩︎

  3. I will take the opportunity to quibble about the way they present their advice on passphrases. My advice is to let your password manager suggest a high entropy password and only use passwords for those things that separate you from your password manager. That’s usually just operating system login and unlocking the password manager. Given how few of these passwords are likely needed, suggesting passphrases over strong passwords seems largely academic. The usability difference between a passphrase and a strong password is tiny; the passphrase might be more memorable, but the password might be quicker to type. ↩︎

  4. Firefox Relay, iCloud Hide My Email, and Fastmail Email Aliases are examples I’m aware of, but many mail providers have similar features. ↩︎

  5. This is where an original QR code is covered with a sticker directing someone to a different site. A QR code on a parking meter for payments is a great example. An attacker can collect parking payments – at inflated prices – for a while before the attack is noticed. ↩︎ ↩︎

  6. The golden rule of the web is: If you are going to enter information into a site, especially when money is involved, type its address in to get to the site[8:1]. ↩︎ ↩︎ ↩︎

  7. Links can also target any app that registers interest in handling URIs. A little more so on phones than desktop computers. Apps generally aren’t as well hardened against attack as browsers, but they are also generally easier to defend, because they have less functionality. The best advice I can give there is to be careful about what apps you install. I liken visiting a web site as a casual encounter, installing an app is much more personal. Either way, the extent to which you are exposed to infection increases with intimacy. ↩︎

  8. Passwords especially. You should never type passwords into a website. That is what a password manager is for. You should only type passwords to get to your password manager. ↩︎ ↩︎

  9. Yes, this is a straight cost, not a risk. There’s no probability involved. ↩︎

  10. There is a very different reason not to click on links in email[12]. A scammer might attempt to convince you that they are someone you trust and get you to send them something you might regret. Like your banking password or money. This is much like the QR code sticker attack[5:1], except that the attacker only has to send you mail that passes mail filters and looks legit. ↩︎

  11. On the web, the place that shows you a link also learns that you clicked it. This is not true for email and QR codes, but that makes very little difference privacy-wise. ↩︎

  12. Clicking on a link in email isn’t always a bad idea. Clicking the link lets the site know that you received their message. That’s the whole point of emails asking you to confirm that you own an email address, so go ahead and click those. Just make sure to close the tab immediately. At least before you put any other information into the site[6:2]. ↩︎

  13. Not like you could have read terms and conditions before scanning the QR code. Or that anyone has time to read them. ↩︎

  14. I’d love to know if there are any operating systems that let you set a different app for QR code links, that seems like it would be a useful feature. ↩︎

  15. The 13 mini is still the only phone in a reasonable form factor that is still relatively current. All other phones are too big. It’s a shame that most web experiences a) run on Safari and b) awful. The latter being the fault of sites, not so much the device. ↩︎

  16. OK, here goes: Unlock your phone, go to the home screen. Open Firefox, go to the tabs view, hit the Private option, open a new tab. Switch to the camera, scan the code, tab the option to open the link. You need to open the tab, because Firefox will use the browsing mode that was last used. ↩︎

Categorieën: Mozilla-nl planet

The Rust Programming Language Blog: Announcing Rust 1.92.0

Mozilla planet - do, 11/12/2025 - 01:00

The Rust team is happy to announce a new version of Rust, 1.92.0. Rust is a programming language empowering everyone to build reliable and efficient software.

If you have a previous version of Rust installed via rustup, you can get 1.92.0 with:

$ rustup update stable

If you don't have it already, you can get rustup from the appropriate page on our website, and check out the detailed release notes for 1.92.0.

If you'd like to help us out by testing future releases, you might consider updating locally to use the beta channel (rustup default beta) or the nightly channel (rustup default nightly). Please report any bugs you might come across!

What's in 1.92.0 stable Deny-by-default never type lints

The language and compiler teams continue to work on stabilization of the never type. In this release the never_type_fallback_flowing_into_unsafe and dependency_on_unit_never_type_fallback future compatibility lints were made deny-by-default, meaning they will cause a compilation error when detected.

It's worth noting that while this can result in compilation errors, it is still a lint; these lints can all be #[allow]ed. These lints also will only fire when building the affected crates directly, not when they are built as dependencies (though a warning will be reported by Cargo in such cases).

These lints detect code which is likely to be broken by the never type stabilization. It is highly advised to fix them if they are reported in your crate graph.

We believe there to be approximately 500 crates affected by this lint. Despite that, we believe this to be acceptable, as lints are not a breaking change and it will allow for stabilizing the never type in the future. For more in-depth justification, see the Language Team's assessment.

unused_must_use no longer warns about Result<(), UninhabitedType>

Rust's unused_must_use lint warns when ignoring the return value of a function, if the function or its return type is annotated with #[must_use]. For instance, this warns if ignoring a return type of Result, to remind you to use ?, or something like .expect("...").

However, some functions return Result, but the error type they use is not actually "inhabited", meaning you cannot construct any values of that type (e.g. the ! or Infallible types).

The unused_must_use lint now no longer warns on Result<(), UninhabitedType>, or on ControlFlow<UninhabitedType, ()>. For instance, it will not warn on Result<(), Infallible>. This avoids having to check for an error that can never happen.

use core::convert::Infallible; fn can_never_fail() -> Result<(), Infallible> { // ... Ok(()) } fn main() { can_never_fail(); }

This is particularly useful with the common pattern of a trait with an associated error type, where the error type may sometimes be infallible:

trait UsesAssocErrorType { type Error; fn method(&self) -> Result<(), Self::Error>; } struct CannotFail; impl UsesAssocErrorType for CannotFail { type Error = core::convert::Infallible; fn method(&self) -> Result<(), Self::Error> { Ok(()) } } struct CanFail; impl UsesAssocErrorType for CanFail { type Error = std::io::Error; fn method(&self) -> Result<(), Self::Error> { Err(std::io::Error::other("something went wrong")) } } fn main() { CannotFail.method(); // No warning CanFail.method(); // Warning: unused `Result` that must be used } Emit unwind tables even when -Cpanic=abort is enabled on linux

Backtraces with -Cpanic=abort previously worked in Rust 1.22 but were broken in Rust 1.23, as we stopped emitting unwind tables with -Cpanic=abort. In Rust 1.45 a workaround in the form of -Cforce-unwind-tables=yes was stabilized.

In Rust 1.92 unwind tables will be emitted by default even when -Cpanic=abort is specified, allowing for backtraces to work properly. If unwind tables are not desired then users should use -Cforce-unwind-tables=no to explicitly disable them being emitted.

Validate input to #[macro_export]

Over the past few releases, many changes were made to the way built-in attributes are processed in the compiler. This should greatly improve the error messages and warnings Rust gives for built-in attributes and especially make these diagnostics more consistent among all of the over 100 built-in attributes.

To give a small example, in this release specifically, Rust became stricter in checking what arguments are allowed to macro_export by upgrading that check to a "deny-by-default lint" that will be reported in dependencies.

Stabilized APIs

These previously stable APIs are now stable in const contexts:

Other changes

Check out everything that changed in Rust, Cargo, and Clippy.

Contributors to 1.92.0

Many people came together to create Rust 1.92.0. We couldn't have done it without all of you. Thanks!

Categorieën: Mozilla-nl planet

Thunderbird Blog: Thunderbird Send Security Audit with OSTIF and 7ASecurity

Mozilla planet - di, 09/12/2025 - 18:07

As we get ready for the Thunderbird Pro launch, we want every service we offer to be secure and worthy of the trust our community places in us. That means being honest about where we stand today and the work we are doing to meet the promises we are making.

Recently we partnered with OSTIF, the Open Source Technology Improvement Fund, and 7ASecurity to perform a full security audit of Thunderbird Send. As previously introduced, Send is an end-to-end encrypted large file sharing service that will be part of the overall Thunderbird Pro subscription suite coming in 2026. It is built on the foundation of the original Firefox Send project, although much has changed since those days.

While the audit focused on Send, the 7ASecurity team also reviewed parts of our shared infrastructure. That extra visibility resulted in meaningful hardening improvements across all of our products.

This was a whitebox audit, which means the auditors had full access to our systems and source code. They reviewed both the client and server sides of the service. They also carried out supply chain analysis, where they examined how our dependencies are managed, and threat modelling, which helps identify how attackers might approach a system even if there is no known exploit today.

The Thunderbird team has already addressed most of the items in the report, including all critical vulnerabilities. This also includes almost all non-critical hardening recommendations.  A few require more time because they relate to the organization of our broader infrastructure. For example, all Thunderbird Pro services currently run under a single AWS account. This is fairly normal in the early stages of building a platform. As the services mature and become more distinct, we will split them into separate accounts for stronger isolation.

The audit highlighted two vulnerabilities. One was critical and one was high. There were also twenty recommendations for further strengthening and improvement. One of the issues involved an API endpoint that had the potential to expose some user data without requiring authentication and another issue created the possibility of a denial of service attack. While neither issue actually happened,  the conditions that made it possible needed to be removed. Both of these were addressed and fixed in April.

The auditors also noted theoretical paths that could lead to privilege escalation, where attackers use one part of a system to gain more access than intended. This does not mean a privilege escalation exists today, but that some patterns could be tightened to prevent them in the future. These concerns apply only to older infrastructure, such as where we were running Appointment Beta. Once we migrate these users from appointment.day to the new appointment.tb.pro, we will retire the older systems entirely.

Another recommendation involves adding build attestations. These allow anyone to verify that a software build came from us and has not been tampered with. This is something we plan to implement in 2026.

Not everything in the report was a list of problems. In fact, the auditors highlighted several positive aspects of the collaboration. Their notes describe a team that was prepared and organized from the beginning, which allowed the audit work to begin without delays. Communication was smooth through email and a shared Element channel. The Send engineering team was consistently helpful and responsive, providing access and information whenever needed. The auditors also appreciated that we gave them full staging visibility, documentation, test accounts and source code. Their updates throughout the process were structured and consistent. The final report even comments on the clarity of the project as a whole, which helped them form a well informed view of our security posture.

The report closes with detailed guidance and commentary, but it also reflects confidence that Thunderbird is taking the right approach to security. That is exactly why we welcome third party audits. Open source only works when everyone can see the work, question it and verify it. Thunderbird Pro will follow those same values as it develops into a complete ecosystem of secure, privacy respecting services.

We will continue improving Send and the rest of our Pro services, and we look forward to sharing more as we get closer to launch. Thank you for being part of this journey and for pushing us to build something stronger.

The full report can be found here.

The post Thunderbird Send Security Audit with OSTIF and 7ASecurity appeared first on The Thunderbird Blog.

Categorieën: Mozilla-nl planet

Data@Mozilla: Incident Report: A compiler bug and JSON

Mozilla planet - di, 09/12/2025 - 16:40

It all started rather inconspicuous: The Data Engineering team filed a bug report about a sudden increase in schema errors at ingestion of telemetry data from Firefox for Android. At that point in time about 0.9% of all incoming pings were not passing our schema validation checks.

The data we were seeing was surprising. Our ingestion endpoint received valid JSON that contained snippets like this:

{ "metrics": { "schema: counter": { "glean.validation.pings_submitted": { "events": 1 } }, ... }, ... }

What we would expect and would pass our schema validation is this:

{ "metrics": { "labeled_counter": { "glean.validation.pings_submitted": { "events": 1 } }, ... }, ... }

The difference? 8 characters:

- "schema: counter": { + "labeled_counter": {

8 different characters that still make up valid JSON, but break validation.

A week later the number of errors kept increasing, affecting up to 2% of all ingested pings from Firefox for Android Beta. That’s worryingly high. That’s enough to drop other work and call an incident.

Aside: Telemetry ingestion

In Firefox the data is collected using the Glean SDK. Data is stored in a local database and eventually assembled into what we call a ping: A bundle of related metrics, gathered in a JSON payload to be transmitted. This JSON document is then POSTed to the Telemetry edge server. From there the decoder eventually picks it up and processes it further. One of the early things it does is verify the received data against one of the pre-defined schemas. When data is coming from the Glean SDK it must pass the pre-defined glean.1.schema.json. This essentially describes which fields to expect in the nested JSON object. One thing it is expecting is a labeled_counter A thing it is NOT expecting is schema: counter. In fact
keys other than the listed ones are forbidden.

The missing schema:_

The data we were receiving from a growing number of clients contained 8 bytes that we didn’t expect in that place: schema: . That 8-character string didn’t even show up in the Glean SDK source code. Where does it come from? Why was it showing up now?

We did receive entirely valid JSON, so it’s unlikely to be simple memory corruption1. More like memory confusion, if that’s a thing.

We know where the payload is constructed. The nested object for labeled metrics is constructed in its own function. It starts with string formatting:

let ping_section = format!("labeled_{}", metric.ping_section());

There’s our 8-character string labeled_ that gets swapped. The Glean SDK is embedded into Firefox inside mozilla-central and compiled with all the other code together. A single candidate for the schema: string exists in that codebase. That’s another clue it could be memory confusion.

My schema? Confused.

I don’t know much about how string formatting in Rust works under the hood, but luckily Mara blogged about it 2 years ago: Behind the Scenes of Rust String Formatting: format_args!() (and then recently improved the implementation2).

So the format! from above expands into something like this:

std::io::_format( // Simplified expansion of format_args!(): std::fmt::Arguments { template: &[Str("labeled_ "), Arg(0)], arguments: &[&metric.ping_section() as &dyn Display], } );

Another clue that the labeled_ string is referenced all by itself and swapping out the pointer to it would be enough to lead to the corrupted data we were seeing.

Architecturing more clues

Whenever we’re faced with data anomalies we start by dissecting the data to figure out if the anomalies are from a particular subset of clients. The hope is that identifying the subset of clients where it happens gives us more clues about the bug itself.

After initially focusing too much on actual devices colleagues helpfully pointed out that the actual split was the device’s architecture3:

Data since 2025-11-11 showing a sharp increase in errors for armeabi-v7a clients

Data since 2025-11-11 showing a sharp increase in errors for armeabi-v7a clients

ARMv8, the 64-bit architecture, did not run into this issue4. ARMv7, purely 32-bit, was the sole driver of this data anomaly. Another clue that something in the code specifically for this architecture was causing this.

Logically unchanged

With a hypothesis what was happening, but no definite answer why, we went to speculative engineering: Let’s avoid the code path that we think is problematic.

By explicitly listing out the different strings we want to have in the JSON payload we avoid the formatting and thus hopefully any memory confusion.

let ping_section = match metric.ping_section() { "boolean" => "labeled_boolean".to_string(), "counter" => "labeled_counter".to_string(), // <snip> _ => format!("labeled_{}", metric.ping_section()), };

This was implemented in 912fc80 and shipped in Glean v66.1.2. It landed in Firefox the same day of the SDK release and made it to Firefox for Android Beta the Friday after. The data shows: It’s working, no more memory confusion!

The number of errors have been on a downturn ever since the fix landed on 2025-11-26

The number of errors have been on a downturn ever since the fix landed on 2025-11-26

A bug gone but still there

The immediate incident-causing data anomaly was mitigated, the bug is not making it to the Firefox 146 release.

But we still didn’t know why this was happening in the first place. My colleagues Yannis and Serge kept working and searching and were finally able to track down what exactly is happening in the code. The bug contains more information on the investigation.

While I was trying to read and understand the disassembly of the broken builds, they went ahead and wrote a tiny emulator (based on the Unicorn engine) that runs just enough of the code to find the offending code path5.

> python ./emulator.py libxul.so Path: libxul.so GNU build id: 1b9e9c8f439b649244c7b3acf649d1f33200f441 Symbol server ID: 8F9C9E1B9B43926444C7B3ACF649D1F30 Please wait, downloading symbols from: https://symbols.mozilla.org/try/libxul.so/8F9C9E1B9B43926444C7B3ACF649D1F30/libxul.so.sym Please wait, uncompressing symbols... Please wait, processing symbols... Proceeding to emulation. Result of emulation: bytearray(b'schema: ') This is a BAD build.

The relevant section of the code boils down to this:

ldr r3, [pc, #0x20c] add r3, pc strd r3, r0, [sp, #0xd0] add r1, sp, #0xd0 bl alloc::fmt::format_inner

The first two instructions build the pointer to the slice in r3, by using a pc-relative offset found in a nearby constant. Then we store that pointer at sp+0xd0, and we put the address sp+0xd0 into r1. So before we reach alloc::fmt::format_inner, r1 points to a stack location that contains a pointer to the slice of interest. The slice lives in .data.rel.ro and contains a pointer to the string, and the length of the string (8). The string itself lives in .rodata.

In good builds the .rodata r3 points to looks like this:

0x06f0c3d4: 0x005dac18 --> "labeled_" 0x06f0c3d8: 0x8 0x06f0c3dc: 0x0185d707 --> "/builds/<snip>/rust/glean-core/src/storage/mod.rs" 0x06f0c3e0: 0x4d

In bad builds however it points to something that has our dreaded schema: string:

0x06d651c8: 0x010aa2e8 --> "schema: " 0x06d651cc: 0x8 0x06d651d0: 0x01a869a7 --> "maintenance: " 0x06d651d4: 0xd 0x06d651d8: 0x01a869b4 --> "storage dir: " 0x06d651dc: 0xd 0x06d651e0: 0x01a869c8 --> "from variant of type " 0x06d651e4: 0x15 0x06d651e8: 0x017f793c --> ": " 0x06d651ec: 0x2

This confirms the suspicion that it’s a compiler/linker bug. Now the question was how to fix that.

Firefox builds with a variety of Clang/LLVM versions. Mozilla uses its own build of LLVM and Clang to build the final applications, the exact version used is updated as soon as possible, but never on release. Sometimes additional patches are applied on top of the Clang release, like some backports fixing other compiler bugs.

After identifying that this is indeed a bug in the linker and that it has already been patched in later LLVM versions, Serge did all the work to bisect the LLVM release to find which patches to apply to Mozilla’s own Clang build. Ultimately he tracked it down to these two patches for LLVM:

With those patches applied, the old code, without our small code rearrangement, does not lead to broken builds anymore.

With the Glean code patched, the ingestion errors dropping and the certainty that we have identified and patched the compiler bug, we can safely ship the next release of Firefox (for Android).

Collaboration

Incidents are stressful situations, but a great place for collaboration across the whole company. The number of people involved in resolving this is long.

Thanks to Eduardo & Ben from Data Engineering for raising the issue.
Thanks to Alessio (my manager) for managing the incident.
Thanks to chutten and Travis (from my team) for brainstorming what caused this and suggesting solutions/workarounds.
Thanks to Donal (Release Management) for fast-tracking the mitigation into a Beta release.
Thanks to Alex (Release Engineering) for some initial investigation into the linker bug.
Thanks to Brad (Data Science) for handling the data analysis side.
Thanks to Yannis and Serge (OS integration) for identifying, finding and patching the linker bug.

Footnotes:

  1. Memory corruption is never “simple”. But if it were memory corruption I would expect data to be broken worse or in other places too. Not just a string swap in a single place.↩︎
  2. That improvement is not yet available to us. The application experiencing the issue was compiled using Rust 1.86.0.↩︎
  3. Our checklist initially omitted architecture. A mistake we since fixed.↩︎
  4. Apparently we do see some errors, but they are so infrequent that we can ignore them for now.↩︎
  5. Later Yannis wrote a script that can identify broken builds purely much quicker, just by searching for the right string patterns.↩︎
Categorieën: Mozilla-nl planet

Firefox Developer Experience: Firefox WebDriver Newsletter 146

Mozilla planet - di, 09/12/2025 - 16:13

WebDriver is a remote control interface that enables introspection and control of user agents. As such it can help developers to verify that their websites are working and performing well with all major browsers. The protocol is standardized by the W3C and consists of two separate specifications: WebDriver classic (HTTP) and the new WebDriver BiDi (Bi-Directional).

This newsletter gives an overview of the work we’ve done as part of the Firefox 146 release cycle.

Contributions

Firefox is an open source project, and we are always happy to receive external code contributions to our WebDriver implementation. We want to give special thanks to everyone who filed issues, bugs and submitted patches.

In Firefox 146 Khalid AlHaddad, who had already contributed to the previous release, submitted two new bug fixes:

WebDriver code is written in JavaScript, Python, and Rust so any web developer can contribute! Read how to setup the work environment and check the list of mentored issues for Marionette, or the list of mentored JavaScript bugs for WebDriver BiDi. Join our chatroom if you need any help to get started!

WebDriver BiDi Marionette
Categorieën: Mozilla-nl planet

Jan-Erik Rediger: Incident Report: A compiler bug and JSON

Mozilla planet - di, 09/12/2025 - 16:01

This article is cross-posted to the Data@Mozilla blog.

It all started rather inconspicuous: The Data Engineering team filed a bug report about a sudden increase in schema errors at ingestion of telemetry data from Firefox for Android. At that point in time about 0.9% of all incoming pings were not passing our schema validation checks.

The data we were seeing was surprising. Our ingestion endpoint received valid JSON that contained snippets like this:

{ "metrics": { "schema: counter": { "glean.validation.pings_submitted": { "events": 1 } }, ... }, ... }

What we would expect and would pass our schema validation is this:

{ "metrics": { "labeled_counter": { "glean.validation.pings_submitted": { "events": 1 } }, ... }, ... }

The difference? 8 characters:

- "schema: counter": { + "labeled_counter": {

8 different characters that still make up valid JSON, but break validation.

A week later the number of errors kept increasing, affecting up to 2% of all ingested pings from Firefox for Android Beta. That's worryingly high. That's enough to drop other work and call an incident.

Aside: Telemetry ingestion

In Firefox the data is collected using the Glean SDK. Data is stored in a local database and eventually assembled into what we call a ping: A bundle of related metrics, gathered in a JSON payload to be transmitted. This JSON document is then POSTed to the Telemetry edge server. From there the decoder eventually picks it up and processes it further. One of the early things it does is verify the received data against one of the pre-defined schemas. When data is coming from the Glean SDK it must pass the pre-defined glean.1.schema.json. This essentially describes which fields to expect in the nested JSON object. One thing it is expecting is a labeled_counter A thing it is NOT expecting is schema: counter. In fact keys other than the listed ones are forbidden.

The missing schema:_

The data we were receiving from a growing number of clients contained 8 bytes that we didn't expect in that place: schema: . That 8-character string didn't even show up in the Glean SDK source code. Where does it come from? Why was it showing up now?

We did receive entirely valid JSON, so it's unlikely to be simple memory corruption1. More like memory confusion, if that's a thing.

We know where the payload is constructed. The nested object for labeled metrics is constructed in its own function. It starts with string formatting:

let ping_section = format!("labeled_{}", metric.ping_section());

There's our 8-character string labeled_ that gets swapped. The Glean SDK is embedded into Firefox inside mozilla-central and compiled with all the other code together. A single candidate for the schema: string exists in that codebase. That's another clue it could be memory confusion.

My schema? Confused.

I don't know much about how string formatting in Rust works under the hood, but luckily Mara blogged about it 2 years ago: Behind the Scenes of Rust String Formatting: format_args!() (and then recently improved the implementation2).

So the format! from above expands into something like this:

std::io::_format( // Simplified expansion of format_args!(): std::fmt::Arguments { template: &[Str("labeled_ "), Arg(0)], arguments: &[&metric.ping_section() as &dyn Display], } );

Another clue that the labeled_ string is referenced all by itself and swapping out the pointer to it would be enough to lead to the corrupted data we were seeing.

Architecturing more clues

Whenever we're faced with data anomalies we start by dissecting the data to figure out if the anomalies are from a particular subset of clients. The hope is that identifying the subset of clients where it happens gives us more clues about the bug itself.

After initially focusing too much on actual devices colleagues helpfully pointed out that the actual split was the device's architecture3:

Data since 2025-11-11 showing a sharp increase in errors for armeabi-v7a clients

ARMv8, the 64-bit architecture, did not run into this issue4. ARMv7, purely 32-bit, was the sole driver of this data anomaly. Another clue that something in the code specifically for this architecture was causing this.

Logically unchanged

With a hypothesis what was happening, but no definite answer why, we went to speculative engineering: Let's avoid the code path that we think is problematic.

By explicitly listing out the different strings we want to have in the JSON payload we avoid the formatting and thus hopefully any memory confusion.

let ping_section = match metric.ping_section() { "boolean" => "labeled_boolean".to_string(), "counter" => "labeled_counter".to_string(), // <snip> _ => format!("labeled_{}", metric.ping_section()), };

This was implemented in 912fc80 and shipped in Glean v66.1.2. It landed in Firefox the same day of the SDK release and made it to Firefox for Android Beta the Friday after. The data shows: It's working, no more memory confusion!

The number of errors have been on a downturn ever since the fix landed on 2025-11-26

A bug gone but still there

The immediate incident-causing data anomaly was mitigated, the bug is not making it to the Firefox 146 release.

But we still didn't know why this was happening in the first place. My colleagues Yannis and Serge kept working and searching and were finally able to track down what exactly is happening in the code. The bug contains more information on the investigation.

While I was trying to read and understand the disassembly of the broken builds, they went ahead and wrote a tiny emulator (based on the Unicorn engine) that runs just enough of the code to find the offending code path5.

> python ./emulator.py libxul.so Path: libxul.so GNU build id: 1b9e9c8f439b649244c7b3acf649d1f33200f441 Symbol server ID: 8F9C9E1B9B43926444C7B3ACF649D1F30 Please wait, downloading symbols from: https://symbols.mozilla.org/try/libxul.so/8F9C9E1B9B43926444C7B3ACF649D1F30/libxul.so.sym Please wait, uncompressing symbols... Please wait, processing symbols... Proceeding to emulation. Result of emulation: bytearray(b'schema: ') This is a BAD build.

The relevant section of the code boils down to this:

ldr r3, [pc, #0x20c] add r3, pc strd r3, r0, [sp, #0xd0] add r1, sp, #0xd0 bl alloc::fmt::format_inner

The first two instructions build the pointer to the slice in r3, by using a pc-relative offset found in a nearby constant. Then we store that pointer at sp+0xd0, and we put the address sp+0xd0 into r1. So before we reach alloc::fmt::format_inner, r1 points to a stack location that contains a pointer to the slice of interest. The slice lives in .data.rel.ro and contains a pointer to the string, and the length of the string (8). The string itself lives in .rodata.

In good builds the .rodata r3 points to looks like this:

0x06f0c3d4: 0x005dac18 --> "labeled_" 0x06f0c3d8: 0x8 0x06f0c3dc: 0x0185d707 --> "/builds/<snip>/rust/glean-core/src/storage/mod.rs" 0x06f0c3e0: 0x4d

In bad builds however it points to something that has our dreaded schema: string:

0x06d651c8: 0x010aa2e8 --> "schema: " 0x06d651cc: 0x8 0x06d651d0: 0x01a869a7 --> "maintenance: " 0x06d651d4: 0xd 0x06d651d8: 0x01a869b4 --> "storage dir: " 0x06d651dc: 0xd 0x06d651e0: 0x01a869c8 --> "from variant of type " 0x06d651e4: 0x15 0x06d651e8: 0x017f793c --> ": " 0x06d651ec: 0x2

This confirms the suspicion that it's a compiler/linker bug. Now the question was how to fix that.

Firefox builds with a variety of Clang/LLVM versions. Mozilla uses its own build of LLVM and Clang to build the final applications, the exact version used is updated as soon as possible, but never on release. Sometimes additional patches are applied on top of the Clang release, like some backports fixing other compiler bugs.

After identifying that this is indeed a bug in the linker and that it has already been patched in later LLVM versions, Serge did all the work to bisect the LLVM release to find which patches to apply to Mozilla's own Clang build. Ultimately he tracked it down to these two patches for LLVM:

With those patches applied, the old code, without our small code rearrangement, does not lead to broken builds anymore.

With the Glean code patched, the ingestion errors dropping and the certainty that we have identified and patched the compiler bug, we can safely ship the next release of Firefox (for Android).

Collaboration

Incidents are stressful situations, but a great place for collaboration across the whole company. The number of people involved in resolving this is long.

Thanks to Eduardo & Ben from Data Engineering for raising the issue.
Thanks to Alessio (my manager) for managing the incident.
Thanks to chutten and Travis (from my team) for brainstorming what caused this and suggesting solutions/workarounds.
Thanks to Donal (Release Management) for fast-tracking the mitigation into a Beta release.
Thanks to Alex (Release Engineering) for some initial investigation into the linker bug.
Thanks to Brad (Data Science) for handling the data analysis side.
Thanks to Yannis and Serge (OS integration) for identifying, finding and patching the linker bug.

Footnotes:

  1. Memory corruption is never "simple". But if it were memory corruption I would expect data to be broken worse or in other places too. Not just a string swap in a single place.

  2. That improvement is not yet available to us. The application experiencing the issue was compiled using Rust 1.86.0.

  3. Our checklist initially omitted architecture. A mistake we since fixed.

  4. Apparently we do see some errors, but they are so infrequent that we can ignore them for now.

  5. Later Yannis wrote a script that can identify broken builds purely much quicker, just by searching for the right string patterns.

Categorieën: Mozilla-nl planet

The Mozilla Blog: Translate the web your way, plus choose the Firefox icon that suits your vibe

Mozilla planet - di, 09/12/2025 - 15:00
A stylized graphic showing a smartphone screen in the background with three square icons in front of it. The left icon is purple with a translation symbol, the middle icon is orange with the Firefox logo, and the right icon is teal with a geometric snowflake-like symbol. The background features a dark grid pattern with soft gradients and small star-like sparkles.

Whenever you open Firefox, we want it to feel like it speaks your language and matches your style. This month, our mobile team is rolling out features inspired by community ideas, user requests and the small everyday moments that make browsing more delightful.

Today we’re bringing three of those ideas to life: on-device translations for iOS, choose your icon for Android and a new search option powered by Perplexity.

Translate the web now on iOS

If you’ve ever tapped a link only to land on a page in a language you don’t read, you know how quickly curiosity can turn into friction. Until now, iOS users didn’t have a built-in way to translate those pages privately within Firefox. That changes today.

We started rolling out translations last week in German, French and Japanese. This week we added Spanish and Portuguese and will roll out more languages soon. 

What’s special about this launch is that it’s not just another translation tool; it’s built on years of Mozilla research and designed to work entirely on your device.

Most browsers send your page content to the cloud before translating it. Firefox takes a different path: Everything happens locally, directly on your phone.

That means:

  • Your content never leaves your device.
  • Nothing is logged or stored.
  • And once the language model is downloaded, translations even work offline.

Building translations this way isn’t easy. Mobile devices have limited memory and battery, so our engineers designed smarter algorithms that translate only what you actually need to read — not the entire page at once.

It’s a small example of something much bigger: Mozilla’s commitment to building features that respect your privacy by default, not as an afterthought.

How it works

When Firefox detects that a page is in a different language from your device settings, it shows the translation icon in the toolbar and will translate to the  language that is set on the device.

Translation icon appears in the toolbar

Customize your Firefox icon – now on Android too

When we released choose your icon on iOS earlier this year, it quickly became one of the most charming ways to personalize Firefox. People loved picking the version that matched their mood, whether  bold, classic or a little bit whimsical.

Now that same experience comes to Android.

Personalize your home screen

On Android, head to: Settings → Customize → App Icon. From there, you can browse a lineup of Firefox styles, including Momo, the warm, joyful fox hugging the Earth. What makes Momo special isn’t just the art itself, but the story behind it.

Momo is just one of the many icons to choose from in Firefox mobile

Momo was originally a five-minute doodle by Dutch illustrator Ruud Hendriks (@heyheymomodraws). Its playful energy immediately resonated with the Firefox team, who saw in it a spark of nostalgia that echoed Firefox’s early logo. Today, that doodle has become the first community-created Firefox app icon.

Ruud’s artwork reminds us  that some of the most delightful product features start as small, genuine ideas from our community.

Read the full interview with Ruud to see how his sketch evolved into an icon now loved by Firefox users worldwide.

Smiling man with Q&A icons and a cartoon earth-hugging character on an orange background. Discover how this fan-made icon made its way into Firefox Read more A new option for search, still on your terms

Search should feel flexible, something you can shape based on what you need. That’s why in our last release we introduced Perplexity, an AI-powered answer engine, as an optional search tool on mobile.

Perplexity provides conversational answers with citations, making it easier to get quick summaries without sifting through multiple pages. And, as always, you choose when or whether to use it.

You’ll find Perplexity in the search bar. It’s available globally and Perplexity maintains strict prohibitions against selling or sharing personal data.

It’s one more way Firefox gives you choice without compromising your values.

Created for everyday browsing

Whether you’re translating the web during your commute, giving your home screen a little personality or trying a new way to search, today’s updates reflect a simple goal: make Firefox feel more personal and more you.

And, just like Momo, many of these ideas were shaped by the Firefox community: the artists, contributors, testers and curious users who help us imagine what the browser can be.

We can’t wait to see how you use what’s new.

Take Firefox with you Download Firefox Mobile

The post Translate the web your way, plus choose the Firefox icon that suits your vibe appeared first on The Mozilla Blog.

Categorieën: Mozilla-nl planet

The Mozilla Blog: You got more with Firefox in 2025

Mozilla planet - di, 09/12/2025 - 09:00

In 2025, we rolled out one update after another, all aimed at making your browsing better — with more flow, speed, choice, and control over your information and experience. Your window to the internet, whether on desktop, mobile, or across all your devices, has gotten an upgrade this year.

More flow: Tab Groups

Try Tab Groups to bring calm to tab chaos — whether you keep three tabs open or three thousand. Color-coded groups make it easy to gather related tabs, stay organized, and jump between projects without losing your place. News you read daily? Weekend hobby research? That big trip you’re planning? There’s a group for that.

Vertical Tabs

Vertical Tabs give you another way to browse — stacking tabs along the side of your window instead of across the top. If you like seeing more of your open tabs at a glance or want a tidier layout, Vertical Tabs give you an alternate view that’s easy to scan and move through.

Address Bar Shortcuts

Address Bar Shortcuts let you jump straight to what you’re looking for using simple, natural keywords. You can quickly search things like open tabs, bookmarks, history, or browser actions by typing helpful shortcuts (like @tabs or @bookmarks) right in the bar — an intuitive way to find what you need without breaking your flow.

More speed: Shake to Summarize (iOS)

On mobile, every moment counts. Shake to Summarize lets you get the key points of what you’re reading with a quick shake or tap. Recipes highlight the steps, sports show the scores, and news pulls out main takeaways — all within seconds. It even earned a Special Mention in TIME’s Best Inventions of 2025. To activate it, you can:

  • Shake your device.
  • Tap the thunderbolt icon in the address bar.
  • Or, from the menu, tap three dots > Summarize Page.
Save Web Apps (Windows)

Firefox lets you save sites to your Windows taskbar and run them as web apps. Once clicked, they open in their own window, so your favorite tools and services are easy to find and quick to launch. You can add any website to the taskbar, just click the web apps icon webappicon  that appears in the address bar. 

Link Previews

Link Previews give you a quick snapshot of what’s behind a link before you open it. No more opening a handful of tabs only to close most of them — just instant context to help you decide where to go next. To activate, click and hold a link for about a second (long press), or right-click on a link and choose ‘Preview Link’ from the menu. 

Unload Tabs

Unload Tabs helps your browser run more efficiently by putting inactive tabs to sleep. They stay visible and ready to reopen instantly when you need them — without slowing down the rest of your browser. Right-click any tab and select ‘Unload Tab’ to try it out.

More choice: AI Chatbots

Unlike browsers that tie you to one default assistant, Firefox lets you choose the AI chatbot you want, right in the sidebar. Keep your preferred assistant within reach, get quick answers without switching tabs, and browse the way that works best for you.

Perplexity

We integrated Perplexity as a secondary search option, offering conversational answers with citations you can trust. It’s a powerful alternative for people who want direct, verifiable information without digging through long pages of results.

Custom Wallpapers

Now you can personalize the look and feel of your browser with curated wallpaper collections or your own images. Create a space that’s uniquely yours by opening a new tab and clicking the pencil icon to start customizing.

More control: PDF Editing

Firefox’s built-in PDF editor now includes signatures and commenting tools. Add notes, mark up documents, sign forms, and review everything from one convenient sidebar — no extra software required.

Visual Search

Visual Search powered by Google Lens lets you look up what you see with a quick right-click on any image. This desktop-only feature makes searching more intuitive and curiosity-driven. For now, it requires Google as your default search engine.

Screen Lock for Private Tabs (Android)

Your private browsing is exactly that: private. Screen Lock protects your private tabs using your device’s biometric authentication — fingerprints, facial recognition, or PIN — keeping your activity secure from anyone who picks up your phone. 

Profile Management

Try profiles to help you keep different parts of your digital life separate. Work vs. personal browsing? School vs. gaming? Create profiles for each, switch between them instantly, and stay focused. Feedback from students, professionals, and contributors helped shape the version rolling out today.

Thanks for a great 2025!

You got a lot more with Firefox this year — from smoother tab management and faster ways to find information to new tools that give you more choice and more control. Wherever the internet takes you, we’ll keep building a browser that puts you first. 

To stay on top of the latest in the new year, be the first to know by checking our release notes or What’s New in Firefox. Thanks for being part of the journey.

Take Firefox with you Download Firefox Mobile

The post You got more with Firefox in 2025  appeared first on The Mozilla Blog.

Categorieën: Mozilla-nl planet

The Mozilla Blog: Meet the artist behind Firefox’s new community-created app icon

Mozilla planet - ma, 08/12/2025 - 17:20

Last year, the Firefox team set out to test something fans requested: choosing a custom app icon. The experiment was simple. Offer a small set of options and see how people use them.

The team created early concepts, but experiment lead Gabrielle Lussier noticed something was missing. The designs were clean and functional, but none captured the playful, emotional spark people associate with Firefox. That led the team to revisit a collection of fan art shared during Firefox’s 20th anniversary, and one illustration stood out immediately: a warm, whimsical drawing of Firefox hugging the Earth by Dutch illustrator Ruud Hendriks (@heyheymomodraws). 

“I love that it is reminiscent of our original logo from 2004, but modernized and simplified. It’s also adorable! How could you not love it!” said Gabrielle.

To select the icon, open Firefox and head to Settings → General (iOS) / Customize (Android) → App Icon. 

First community-created app icon now available in Firefox

Ruud is known for the charming, joyful characters in his comic series heyheymomo, and he brings that same energy to this design. He originally created the artwork as a quick doodle for fun. Today, it is the first community-created app icon in Firefox.

In the Q&A below, Ruud shares how the sketch came to life, what inspired it, and what it means to see his work appear inside a browser he has used for years.

Can you tell us a bit about yourself and what inspired you to participate in last year’s Firefox 20th anniversary fan art challenge?

The funny thing is, I participated before the challenge was even a thing! One day, I didn’t know what to draw and somehow felt inspired by the cute little fox icon in my dock. I drew my own version as a super loose doodle, completely on a whim, in just a few minutes. I thought it came out pretty cute, so I posted it on my social media just for fun. People vibed with it, and the Mozilla social team picked it up. A few weeks later, I got a message asking if I wanted to submit it for the challenge since they really liked it. Of course I said yes!

What does Firefox mean to you personally, as a brand, a browser, or a community?

I’ve been on the internet for a long time. Firefox has been my favourite browser since forever, and I’m a bit of a creature of habit, so it’s always stuck with me. I like how lightweight and simple it is. Plus, as a visually minded person, I totally judge books by their covers — and I’ve always loved the Firefox icon. It’s so appealing that it made me want to draw it in the first place.

Momo is just one of the many icons you can select Where did the idea for your “Firefox hugging the Earth” artwork come from?

It’s my little homage to the older Firefox logo, the one that made me a Firefox fan. The new one is very stylish, but the older one has always had a special place in my heart. My own work is usually very cutesy, with smiley faces and friendly characters, so I just drew my own version of it in that style.

This looks hand-drawn. What tools or techniques did you use to create it?

The initial five-minute doodle was just a quick sketch on my iPad using the app Procreate. Since Mozilla was interested in making it an actual icon, I later created a high-resolution, smoother version using vector art.

How did you feel when you learned your artwork would become one of the official Firefox app icons?

As a longtime Firefox fan, I was over the moon and couldn’t believe all of this came from just a silly doodle I did on a whim. I think that’s the beauty of the internet — how something small and spontaneous can take off like that. I’m really honoured, and I hope you all like my silly, little icon.

What a fan-made icon says about how we build

Ruud’s icon shows how product features can come from small, genuine ideas. His artwork delivered exactly what the team set out to explore: a bit of delight, a touch of nostalgia, and a visual style that feels true to Firefox. This project reflects how Mozilla builds. We listen, we iterate, and we look for ways to bring community creativity into the product. Ruud’s contribution shows how users and artists can shape Firefox in ways that feel both personal and unexpected.

Ruud Hendriks is an illustrator from the Netherlands, specializing in cute and whimsical characters. He has extensive experience working on children’s toys, apps, and games, and now focuses primarily on his own comic series, heyheymomo, which follows the adventures of a dog and frog who are best friends.

His work is lighthearted and designed to brighten your day, even if just for a moment. You can explore his comics on Instagram @heyheymomodraws and find prints at heyheymomo.com.

The post Meet the artist behind Firefox’s new community-created app icon  appeared first on The Mozilla Blog.

Categorieën: Mozilla-nl planet

The Rust Programming Language Blog: Making it easier to sponsor Rust contributors

Mozilla planet - ma, 08/12/2025 - 01:00

TLDR: You can now find a list of Rust contributors that you can sponsor on this page.

Same as with many other open-source projects, Rust depends on a large number of contributors, many of whom make Rust better on a volunteer basis or are funded only for a fraction of their open-source contributions.

Supporting these contributors is vital for the long-term health of the Rust language and its toolchain, so that it can keep its current level of quality, but also evolve going forward. Of course, this is nothing new, and there are currently several ongoing efforts to provide stable and sustainable funding for Rust maintainers, such as the Rust Foundation Maintainer Fund or the RustNL Maintainers Fund. We are very happy about that!

That being said, there are multiple ways of supporting the development of Rust. One of them is sponsoring individual Rust contributors directly, through services like GitHub Sponsors. This makes it possible even for individuals or small companies to financially support their favourite contributors. Every bit of funding helps!

Previously, if you wanted to sponsor someone who works on Rust, you had to go on a detective hunt to figure out who are the people contributing to the Rust toolchain, if they are receiving sponsorships and through which service. This was a lot of work that could provide a barrier to sponsorships. So we simplified it!

Now we have a dedicated Funding page on the Rust website, which helpfully shows members of the Rust Project that are currently accepting funds through sponsoring1. You can click on the name of a contributor to find out what teams they are a part of and what kind of work they do in the Rust Project.

Note that the list of contributors accepting funding on this page is non-exhaustive. We made it opt in, so that contributors can decide on their own whether they want to be listed there or not.

If you ever wanted to support the development of Rust "in the small", it is now simpler than ever.

  1. The order of people on the funding page is shuffled on every page load to reduce unnecessary ordering bias.

Categorieën: Mozilla-nl planet

Rewiring Mozilla: Doing for AI what we did for the web

Mozilla Blog - do, 20/11/2025 - 16:00
The Mozilla logo in green on a black background

AI isn’t just another tech trend — it’s at the heart of  most apps, tools and technology we use today. It enables remarkable things: new ways to create and collaborate and communicate. But AI is also letting us down, filling the internet with slop, creating huge social and economic risks — and further concentrating power over how tech works in the hands of a few.

This leaves us with a choice: push the trajectory of AI in a direction that’s good for humanity — or just let the slop pour out and the monopolies grow. For Mozilla, the choice is clear. We choose humanity. 

Mozilla has always been focused on making the internet a better place. Which is why pushing AI in a different direction than it’s currently headed is the core focus of our strategy right now. As AI becomes a fundamental component of everything digital — everything people build on the internet — it’s imperative that we step in to shape where it goes. 

This post is the first in a series that will lay out Mozilla’s evolving strategy to do for AI what we did for the web.

What did we do for the web? 

Twenty five years ago, Microsoft Internet Explorer had 95% browser market share — controlling how most people saw the internet, and who could build what and on what terms. Mozilla was born to change this. Firefox challenged Microsoft’s monopoly control of the web, and dropped Internet Explorer’s market share to 55% in just a few short years. 

The result was a very different internet. For most people, the internet was different because Firefox made it faster and richer — and blocked the annoying pop up ads that were pervasive at the time. It did even more for developers: Firefox was a rocketship for the growth of open standards and open source, decentralizing who controlled the technology used to build things on the internet. This ushered in the web 2.0 era. 

How did Mozilla do this? By building a non-profit tech company around the values in the Mozilla Manifesto — values like privacy, openness and trust. And by gathering a global community of tens  of thousands — a rebel alliance of sorts — to build an alternative to the big tech behemoth of the time. 

What does success look like? 

This is what we intend to do again: grow an alliance of people, communities, companies who envision — and want to build — a different future for AI.

What does ‘different’ look like? There are millions of good answers to this question. If your native tongue isn’t a major internet language like English or Chinese, it might be AI that has nuance in the language you speak. If you are a developer or a startup, it might be having open source AI building blocks that are affordable, flexible and let you truly own what you create. And if you are, well, anyone, it’s probably apps and services that become more useful and delightful as they add AI — and that are genuinely trustworthy and respectful of who we are as humans. The common threads: agency, diversity, choice. 

Our task is to create a future for AI that is built around these values. We’ve started to rewire Mozilla to take on this task — and developed a new strategy focused just as much on AI as it is on the web. At the heart of this strategy is a double bottom line framework — a way to measure our progress against both mission and money: 

Double bottom lineIn the worldIn MozillaMissionEmpower people with tech that promotes agency and choice – make AI for and about people. Build AI that puts humanity first
100% of Mozilla orgs building AI that advances the Mozilla Manifesto.MoneyDecentralize the tech industry – and create an tech ecosystem where the ‘people part’ of AI can flourishRadically diversify our revenue. 20% yearly growth in non-search revenue. 3+ companies with $25M+ revenue.

Mozilla has always had an implicit double bottom line. The strategy we developed this year makes this double bottom line explicit — and ties it back to making AI more open and trustworthy. Over the next three years, all of the organizations in Mozilla’s portfolio will design their strategies — and measure their success — against this double bottom line. 

What will we build? 

As we’ve rewired Mozilla, we’ve not only laid out a new strategy — we have also brought in new leaders and expanded our portfolio of responsible tech companies. This puts us on a strong footing. The next step is the most important one: building new things — real technology and products and services that start to carve a different path for AI.

While it is still early days, all of the organizations across Mozilla are well underway with this piece of the puzzle. Each is focused on at least one of three areas of focus in our strategy:

Open source AI
— for developers
Public interest AI
— by and for communities
Trusted AI experiences
— for everyone 
Focus: grow a decentralized open source AI ecosystem that matches the capabilities of Big AI — and that enables people everywhere to build with AI on their own terms.Focus: work with communities everywhere to build technology that reflects their vision of who AI and tech should work, especially where the market won’t build it for them.Focus: create trusted AI-driven products that give people new ways to interact with the web — with user choice and openness as guiding principles.Early examples: Mozilla.ai’s Choice First Stack, a unified open-source stack that simplifies building and testing modern AI agents. Also, llamafile for local AI.Early examples: the Mozilla Data Collective, home to Common Voice, which makes it possible to train and tune AI models in 300+ languages, accents and dialects. Early examples: recent Firefox AI experiments, which will evolve into AI Window in early 2026 — offering an opt-in way to choose models and add AI features in a browser you trust. 

The classic versions of Firefox and Thunderbird are still at the heart of what Mozilla does. These remain our biggest areas of investment — and neither of these products will force you to use AI. At the same time, you will see much more from Mozilla on the AI front in coming years. And, you will see us invest in other double bottom line companies trying to point AI in a better direction

We need to do this — together

These are the stakes: if we can’t push AI in a better direction, the internet — a place where 6 billion of us now spend much of our lives — will get much much worse. If we want to shape the future of the web and the internet, we also need to shape the future of AI. 

For Mozilla, whether or not to tackle this challenge isn’t a question anymore. We need to do this. The question is: how? The high level strategy that I’ve laid out is our answer. It doesn’t prescribe all the details — but it does give us a direction to point ourselves and our resources. Of course, we know there is still a HUGE amount to figure out as we build things — and we know that we can’t do this alone.

Which means it’s incredibly important to figure out: who can we walk beside? Who are our allies? The there is a growing community of people who believe the internet is alive and well — and who are dedicating themselves to bending the future of AI to keep it that way. They may not all use the same words or be building exactly the same thing, but a rebel alliance of sorts is gathering. Mozilla sees itself as part of this alliance. Our plan is to work with as many of you as possible. And to help the alliance grow — and win — just as we did in the web era. 

You can read the full strategy document here. Next up in this series: Building A LAMP Stack for AI. Followed by: A Double Bottom Line for Tech and The Mozilla Manifesto in the Era of AI

The post Rewiring Mozilla: Doing for AI what we did for the web appeared first on The Mozilla Blog.

Categorieën: Mozilla-nl planet

Firefox tab groups just got an upgrade, thanks to your feedback

Mozilla Blog - ma, 17/11/2025 - 15:00
Firefox tab grouping with cursor selecting “Recipes” and a dropdown list; “Paris Trip” group visible

Tab groups have become one of Firefox’s most loved ways to stay organized — over 18 million people have used the feature since it launched earlier this year. Since then, we’ve been listening closely to feedback from the Mozilla Connect community to make this long-awaited feature even more helpful.

We’ve just concluded a round of highly requested tab groups updates that make it easier than ever to stay focused, organized, and productive. Check out what we’ve been up to, and if you haven’t tried tab groups yet, here’s a helpful starting guide. 

Preview tab group contents on hover

Starting in Firefox 145, you can peek inside a group without expanding it. Whether you’re checking a stash of tabs set aside for deep research or quickly scanning a group to find the right meeting notes doc, hover previews give you the context you need — instantly.

Keep the active tab visible in a collapsed group — and drag tabs into it

Since Firefox 142, when you collapse a group, the tab you’re working in remains visible. It’s a small but mighty improvement that reduces interruptions. And, starting in Firefox 143, you can drag a tab directly into a collapsed group without expanding it. It’s a quick, intuitive way to stay organized while reducing on-screen clutter.

Each of these ideas came from your feedback on Mozilla Connect. We’re grateful for your engagement, creativity, and patience as our team works to improve Tab Groups.

What’s next for tab groups

We’ve got a big, healthy stash of great ideas and suggestions to explore, but we’d love to hear more from you on two areas of long-term interest: 

  • Improving the usefulness and ease of use of saved tab groups. We’re curious how you’re using them and how we can make the experience more helpful to you. What benefits do they bring to your workflow compared to bookmarks? 
  • Workspaces. Some of you have requested a way to separate contexts by creating workspaces — sets of tabs and tab groups that are entirely isolated from each other, yet remain available within a single browser window. We are curious about your workspace use cases and where context separation via window management or profiles doesn’t meet your workflow needs. Is collaboration an important feature of the workspaces for you? 

Have ideas and suggestions? Let us know in this Mozilla Connect thread!

Take control of your internet Download Firefox

The post Firefox tab groups just got an upgrade, thanks to your feedback appeared first on The Mozilla Blog.

Categorieën: Mozilla-nl planet

Pagina's