{"id":13787396,"url":"https://github.com/aflnet/aflnet","last_synced_at":"2025-05-12T00:31:03.886Z","repository":{"id":38693048,"uuid":"236618759","full_name":"aflnet/aflnet","owner":"aflnet","description":"AFLNet: A Greybox Fuzzer for Network Protocols (https://thuanpv.github.io/publications/AFLNet_ICST20.pdf)","archived":false,"fork":false,"pushed_at":"2024-07-25T23:35:29.000Z","size":6714,"stargazers_count":872,"open_issues_count":34,"forks_count":194,"subscribers_count":22,"default_branch":"master","last_synced_at":"2024-11-18T00:37:24.441Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/aflnet.png","metadata":{"files":{"readme":"README-AFL.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-01-27T23:31:35.000Z","updated_at":"2024-11-11T19:17:49.000Z","dependencies_parsed_at":"2024-07-18T02:45:34.412Z","dependency_job_id":"a5e98262-089d-42d4-a825-0158df722815","html_url":"https://github.com/aflnet/aflnet","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aflnet%2Faflnet","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aflnet%2Faflnet/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aflnet%2Faflnet/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aflnet%2Faflnet/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/aflnet","download_url":"https://codeload.github.com/aflnet/aflnet/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253655802,"owners_count":21943068,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-03T20:00:33.694Z","updated_at":"2025-05-12T00:30:58.870Z","avatar_url":"https://github.com/aflnet.png","language":"C","readme":"# american fuzzy lop\n\n[![Build Status](https://travis-ci.org/google/AFL.svg?branch=master)](https://travis-ci.org/google/AFL)\n\nOriginally developed by Michal Zalewski \u003clcamtuf@google.com\u003e.\n\nSee [QuickStartGuide.txt](docs/QuickStartGuide.txt) if you don't have time to read\nthis file.\n\n## 1) Challenges of guided fuzzing\n\nFuzzing is one of the most powerful and proven strategies for identifying\nsecurity issues in real-world software; it is responsible for the vast\nmajority of remote code execution and privilege escalation bugs found to date\nin security-critical software.\n\nUnfortunately, fuzzing is also relatively shallow; blind, random mutations\nmake it very unlikely to reach certain code paths in the tested code, leaving\nsome vulnerabilities firmly outside the reach of this technique.\n\nThere have been numerous attempts to solve this problem. One of the early\napproaches - pioneered by Tavis Ormandy - is corpus distillation. The method\nrelies on coverage signals to select a subset of interesting seeds from a\nmassive, high-quality corpus of candidate files, and then fuzz them by\ntraditional means. The approach works exceptionally well, but requires such\na corpus to be readily available. In addition, block coverage measurements\nprovide only a very simplistic understanding of program state, and are less\nuseful for guiding the fuzzing effort in the long haul.\n\nOther, more sophisticated research has focused on techniques such as program\nflow analysis (\"concolic execution\"), symbolic execution, or static analysis.\nAll these methods are extremely promising in experimental settings, but tend\nto suffer from reliability and performance problems in practical uses - and\ncurrently do not offer a viable alternative to \"dumb\" fuzzing techniques.\n\n## 2) The afl-fuzz approach\n\nAmerican Fuzzy Lop is a brute-force fuzzer coupled with an exceedingly simple\nbut rock-solid instrumentation-guided genetic algorithm. It uses a modified\nform of edge coverage to effortlessly pick up subtle, local-scale changes to\nprogram control flow.\n\nSimplifying a bit, the overall algorithm can be summed up as:\n\n  1) Load user-supplied initial test cases into the queue,\n\n  2) Take next input file from the queue,\n\n  3) Attempt to trim the test case to the smallest size that doesn't alter\n     the measured behavior of the program,\n\n  4) Repeatedly mutate the file using a balanced and well-researched variety\n     of traditional fuzzing strategies,\n\n  5) If any of the generated mutations resulted in a new state transition\n     recorded by the instrumentation, add mutated output as a new entry in the\n     queue.\n\n  6) Go to 2.\n\nThe discovered test cases are also periodically culled to eliminate ones that\nhave been obsoleted by newer, higher-coverage finds; and undergo several other\ninstrumentation-driven effort minimization steps.\n\nAs a side result of the fuzzing process, the tool creates a small,\nself-contained corpus of interesting test cases. These are extremely useful\nfor seeding other, labor- or resource-intensive testing regimes - for example,\nfor stress-testing browsers, office applications, graphics suites, or\nclosed-source tools.\n\nThe fuzzer is thoroughly tested to deliver out-of-the-box performance far\nsuperior to blind fuzzing or coverage-only tools.\n\n## 3) Instrumenting programs for use with AFL\n\nWhen source code is available, instrumentation can be injected by a companion\ntool that works as a drop-in replacement for gcc or clang in any standard build\nprocess for third-party code.\n\nThe instrumentation has a fairly modest performance impact; in conjunction with\nother optimizations implemented by afl-fuzz, most programs can be fuzzed as fast\nor even faster than possible with traditional tools.\n\nThe correct way to recompile the target program may vary depending on the\nspecifics of the build process, but a nearly-universal approach would be:\n\n```shell\n$ CC=/path/to/afl/afl-gcc ./configure\n$ make clean all\n```\n\nFor C++ programs, you'd would also want to set `CXX=/path/to/afl/afl-g++`.\n\nThe clang wrappers (afl-clang and afl-clang++) can be used in the same way;\nclang users may also opt to leverage a higher-performance instrumentation mode,\nas described in llvm_mode/README.llvm.\n\nWhen testing libraries, you need to find or write a simple program that reads\ndata from stdin or from a file and passes it to the tested library. In such a\ncase, it is essential to link this executable against a static version of the\ninstrumented library, or to make sure that the correct .so file is loaded at\nruntime (usually by setting `LD_LIBRARY_PATH`). The simplest option is a static\nbuild, usually possible via:\n\n```shell\n$ CC=/path/to/afl/afl-gcc ./configure --disable-shared\n```\n\nSetting `AFL_HARDEN=1` when calling 'make' will cause the CC wrapper to\nautomatically enable code hardening options that make it easier to detect\nsimple memory bugs. Libdislocator, a helper library included with AFL (see\nlibdislocator/README.dislocator) can help uncover heap corruption issues, too.\n\nPS. ASAN users are advised to review [notes_for_asan.txt](docs/notes_for_asan.txt) file for important\ncaveats.\n\n## 4) Instrumenting binary-only apps\n\nWhen source code is *NOT* available, the fuzzer offers experimental support for\nfast, on-the-fly instrumentation of black-box binaries. This is accomplished\nwith a version of QEMU running in the lesser-known \"user space emulation\" mode.\n\nQEMU is a project separate from AFL, but you can conveniently build the\nfeature by doing:\n\n```shell\n$ cd qemu_mode\n$ ./build_qemu_support.sh\n```\n\nFor additional instructions and caveats, see qemu_mode/README.qemu.\n\nThe mode is approximately 2-5x slower than compile-time instrumentation, is\nless conductive to parallelization, and may have some other quirks.\n\n## 5) Choosing initial test cases\n\nTo operate correctly, the fuzzer requires one or more starting file that\ncontains a good example of the input data normally expected by the targeted\napplication. There are two basic rules:\n\n  - Keep the files small. Under 1 kB is ideal, although not strictly necessary.\n    For a discussion of why size matters, see [perf_tips.txt](docs/perf_tips.txt).\n\n  - Use multiple test cases only if they are functionally different from\n    each other. There is no point in using fifty different vacation photos\n    to fuzz an image library.\n\nYou can find many good examples of starting files in the testcases/ subdirectory\nthat comes with this tool.\n\nPS. If a large corpus of data is available for screening, you may want to use\nthe afl-cmin utility to identify a subset of functionally distinct files that\nexercise different code paths in the target binary.\n\n## 6) Fuzzing binaries\n\nThe fuzzing process itself is carried out by the afl-fuzz utility. This program\nrequires a read-only directory with initial test cases, a separate place to\nstore its findings, plus a path to the binary to test.\n\nFor target binaries that accept input directly from stdin, the usual syntax is:\n\n```shell\n$ ./afl-fuzz -i testcase_dir -o findings_dir /path/to/program [...params...]\n```\n\nFor programs that take input from a file, use '@@' to mark the location in\nthe target's command line where the input file name should be placed. The\nfuzzer will substitute this for you:\n\n```shell\n$ ./afl-fuzz -i testcase_dir -o findings_dir /path/to/program @@\n```\n\nYou can also use the -f option to have the mutated data written to a specific\nfile. This is useful if the program expects a particular file extension or so.\n\nNon-instrumented binaries can be fuzzed in the QEMU mode (add -Q in the command\nline) or in a traditional, blind-fuzzer mode (specify -n).\n\nYou can use -t and -m to override the default timeout and memory limit for the\nexecuted process; rare examples of targets that may need these settings touched\ninclude compilers and video decoders.\n\nTips for optimizing fuzzing performance are discussed in [perf_tips.txt](docs/perf_tips.txt).\n\nNote that afl-fuzz starts by performing an array of deterministic fuzzing\nsteps, which can take several days, but tend to produce neat test cases. If you\nwant quick \u0026 dirty results right away - akin to zzuf and other traditional\nfuzzers - add the -d option to the command line.\n\n## 7) Interpreting output\n\nSee the [status_screen.txt](docs/status_screen.txt) file for information on\nhow to interpret the displayed stats and monitor the health of the process.\nBe sure to consult this file especially if any UI elements are highlighted in\nred.\n\nThe fuzzing process will continue until you press Ctrl-C. At minimum, you want\nto allow the fuzzer to complete one queue cycle, which may take anywhere from a\ncouple of hours to a week or so.\n\nThere are three subdirectories created within the output directory and updated\nin real time:\n\n  - queue/   - test cases for every distinctive execution path, plus all the\n               starting files given by the user. This is the synthesized corpus\n               mentioned in section 2.\n               Before using this corpus for any other purposes, you can shrink\n               it to a smaller size using the afl-cmin tool. The tool will find\n               a smaller subset of files offering equivalent edge coverage.\n\n  - crashes/ - unique test cases that cause the tested program to receive a\n               fatal signal (e.g., SIGSEGV, SIGILL, SIGABRT). The entries are\n               grouped by the received signal.\n\n  - hangs/   - unique test cases that cause the tested program to time out. The\n               default time limit before something is classified as a hang is\n               the larger of 1 second and the value of the -t parameter.\n               The value can be fine-tuned by setting AFL_HANG_TMOUT, but this\n               is rarely necessary.\n\nCrashes and hangs are considered \"unique\" if the associated execution paths\ninvolve any state transitions not seen in previously-recorded faults. If a\nsingle bug can be reached in multiple ways, there will be some count inflation\nearly in the process, but this should quickly taper off.\n\nThe file names for crashes and hangs are correlated with parent, non-faulting\nqueue entries. This should help with debugging.\n\nWhen you can't reproduce a crash found by afl-fuzz, the most likely cause is\nthat you are not setting the same memory limit as used by the tool. Try:\n\n```shell\n$ LIMIT_MB=50\n$ ( ulimit -Sv $[LIMIT_MB \u003c\u003c 10]; /path/to/tested_binary ... )\n```\n\nChange LIMIT_MB to match the -m parameter passed to afl-fuzz. On OpenBSD,\nalso change -Sv to -Sd.\n\nAny existing output directory can be also used to resume aborted jobs; try:\n\n```shell\n$ ./afl-fuzz -i- -o existing_output_dir [...etc...]\n```\n\nIf you have gnuplot installed, you can also generate some pretty graphs for any\nactive fuzzing task using afl-plot. For an example of how this looks like,\nsee [http://lcamtuf.coredump.cx/afl/plot/](http://lcamtuf.coredump.cx/afl/plot/).\n\n## 8) Parallelized fuzzing\n\nEvery instance of afl-fuzz takes up roughly one core. This means that on\nmulti-core systems, parallelization is necessary to fully utilize the hardware.\nFor tips on how to fuzz a common target on multiple cores or multiple networked\nmachines, please refer to [parallel_fuzzing.txt](docs/parallel_fuzzing.txt).\n\nThe parallel fuzzing mode also offers a simple way for interfacing AFL to other\nfuzzers, to symbolic or concolic execution engines, and so forth; again, see the\nlast section of [parallel_fuzzing.txt](docs/parallel_fuzzing.txt) for tips.\n\n## 9) Fuzzer dictionaries\n\nBy default, afl-fuzz mutation engine is optimized for compact data formats -\nsay, images, multimedia, compressed data, regular expression syntax, or shell\nscripts. It is somewhat less suited for languages with particularly verbose and\nredundant verbiage - notably including HTML, SQL, or JavaScript.\n\nTo avoid the hassle of building syntax-aware tools, afl-fuzz provides a way to\nseed the fuzzing process with an optional dictionary of language keywords,\nmagic headers, or other special tokens associated with the targeted data type\n-- and use that to reconstruct the underlying grammar on the go:\n\n  [http://lcamtuf.blogspot.com/2015/01/afl-fuzz-making-up-grammar-with.html](http://lcamtuf.blogspot.com/2015/01/afl-fuzz-making-up-grammar-with.html)\n\nTo use this feature, you first need to create a dictionary in one of the two\nformats discussed in dictionaries/README.dictionaries; and then point the fuzzer\nto it via the -x option in the command line.\n\n(Several common dictionaries are already provided in that subdirectory, too.)\n\nThere is no way to provide more structured descriptions of the underlying\nsyntax, but the fuzzer will likely figure out some of this based on the\ninstrumentation feedback alone. This actually works in practice, say:\n\n  [http://lcamtuf.blogspot.com/2015/04/finding-bugs-in-sqlite-easy-way.html](http://lcamtuf.blogspot.com/2015/04/finding-bugs-in-sqlite-easy-way.html)\n\nPS. Even when no explicit dictionary is given, afl-fuzz will try to extract\nexisting syntax tokens in the input corpus by watching the instrumentation\nvery closely during deterministic byte flips. This works for some types of\nparsers and grammars, but isn't nearly as good as the -x mode.\n\nIf a dictionary is really hard to come by, another option is to let AFL run\nfor a while, and then use the token capture library that comes as a companion\nutility with AFL. For that, see libtokencap/README.tokencap.\n\n## 10) Crash triage\n\nThe coverage-based grouping of crashes usually produces a small data set that\ncan be quickly triaged manually or with a very simple GDB or Valgrind script.\nEvery crash is also traceable to its parent non-crashing test case in the\nqueue, making it easier to diagnose faults.\n\nHaving said that, it's important to acknowledge that some fuzzing crashes can be\ndifficult to quickly evaluate for exploitability without a lot of debugging and\ncode analysis work. To assist with this task, afl-fuzz supports a very unique\n\"crash exploration\" mode enabled with the -C flag.\n\nIn this mode, the fuzzer takes one or more crashing test cases as the input,\nand uses its feedback-driven fuzzing strategies to very quickly enumerate all\ncode paths that can be reached in the program while keeping it in the\ncrashing state.\n\nMutations that do not result in a crash are rejected; so are any changes that\ndo not affect the execution path.\n\nThe output is a small corpus of files that can be very rapidly examined to see\nwhat degree of control the attacker has over the faulting address, or whether\nit is possible to get past an initial out-of-bounds read - and see what lies\nbeneath.\n\nOh, one more thing: for test case minimization, give afl-tmin a try. The tool\ncan be operated in a very simple way:\n\n```shell\n$ ./afl-tmin -i test_case -o minimized_result -- /path/to/program [...]\n```\n\nThe tool works with crashing and non-crashing test cases alike. In the crash\nmode, it will happily accept instrumented and non-instrumented binaries. In the\nnon-crashing mode, the minimizer relies on standard AFL instrumentation to make\nthe file simpler without altering the execution path.\n\nThe minimizer accepts the -m, -t, -f and @@ syntax in a manner compatible with\nafl-fuzz.\n\nAnother recent addition to AFL is the afl-analyze tool. It takes an input\nfile, attempts to sequentially flip bytes, and observes the behavior of the\ntested program. It then color-codes the input based on which sections appear to\nbe critical, and which are not; while not bulletproof, it can often offer quick\ninsights into complex file formats. More info about its operation can be found\nnear the end of [technical_details.txt](docs/technical_details.txt).\n\n## 11) Going beyond crashes\n\nFuzzing is a wonderful and underutilized technique for discovering non-crashing\ndesign and implementation errors, too. Quite a few interesting bugs have been\nfound by modifying the target programs to call abort() when, say:\n\n  - Two bignum libraries produce different outputs when given the same\n    fuzzer-generated input,\n\n  - An image library produces different outputs when asked to decode the same\n    input image several times in a row,\n\n  - A serialization / deserialization library fails to produce stable outputs\n    when iteratively serializing and deserializing fuzzer-supplied data,\n\n  - A compression library produces an output inconsistent with the input file\n    when asked to compress and then decompress a particular blob.\n\nImplementing these or similar sanity checks usually takes very little time;\nif you are the maintainer of a particular package, you can make this code\nconditional with `#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION` (a flag also\nshared with libfuzzer) or `#ifdef __AFL_COMPILER` (this one is just for AFL).\n\n## 12) Common-sense risks\n\nPlease keep in mind that, similarly to many other computationally-intensive\ntasks, fuzzing may put strain on your hardware and on the OS. In particular:\n\n  - Your CPU will run hot and will need adequate cooling. In most cases, if\n    cooling is insufficient or stops working properly, CPU speeds will be\n    automatically throttled. That said, especially when fuzzing on less\n    suitable hardware (laptops, smartphones, etc), it's not entirely impossible\n    for something to blow up.\n\n  - Targeted programs may end up erratically grabbing gigabytes of memory or\n    filling up disk space with junk files. AFL tries to enforce basic memory\n    limits, but can't prevent each and every possible mishap. The bottom line\n    is that you shouldn't be fuzzing on systems where the prospect of data loss\n    is not an acceptable risk.\n\n  - Fuzzing involves billions of reads and writes to the filesystem. On modern\n    systems, this will be usually heavily cached, resulting in fairly modest\n    \"physical\" I/O - but there are many factors that may alter this equation.\n    It is your responsibility to monitor for potential trouble; with very heavy\n    I/O, the lifespan of many HDDs and SSDs may be reduced.\n\n    A good way to monitor disk I/O on Linux is the 'iostat' command:\n\n```shell\n    $ iostat -d 3 -x -k [...optional disk ID...]\n```\n\n## 13) Known limitations \u0026 areas for improvement\n\nHere are some of the most important caveats for AFL:\n\n  - AFL detects faults by checking for the first spawned process dying due to\n    a signal (SIGSEGV, SIGABRT, etc). Programs that install custom handlers for\n    these signals may need to have the relevant code commented out. In the same\n    vein, faults in child processed spawned by the fuzzed target may evade\n    detection unless you manually add some code to catch that.\n\n  - As with any other brute-force tool, the fuzzer offers limited coverage if\n    encryption, checksums, cryptographic signatures, or compression are used to\n    wholly wrap the actual data format to be tested.\n\n    To work around this, you can comment out the relevant checks (see\n    experimental/libpng_no_checksum/ for inspiration); if this is not possible,\n    you can also write a postprocessor, as explained in\n    experimental/post_library/.\n\n  - There are some unfortunate trade-offs with ASAN and 64-bit binaries. This\n    isn't due to any specific fault of afl-fuzz; see [notes_for_asan.txt](docs/notes_for_asan.txt)\n    for tips.\n\n  - There is no direct support for fuzzing network services, background\n    daemons, or interactive apps that require UI interaction to work. You may\n    need to make simple code changes to make them behave in a more traditional\n    way. Preeny may offer a relatively simple option, too - see:\n    https://github.com/zardus/preeny\n\n    Some useful tips for modifying network-based services can be also found at:\n    https://www.fastly.com/blog/how-to-fuzz-server-american-fuzzy-lop\n\n  - AFL doesn't output human-readable coverage data. If you want to monitor\n    coverage, use afl-cov from Michael Rash: https://github.com/mrash/afl-cov\n\n  - Occasionally, sentient machines rise against their creators. If this\n    happens to you, please consult http://lcamtuf.coredump.cx/prep/.\n\nBeyond this, see INSTALL for platform-specific tips.\n\n## 14) Special thanks\n\nMany of the improvements to afl-fuzz wouldn't be possible without feedback,\nbug reports, or patches from:\n\n```\n  Jann Horn                             Hanno Boeck\n  Felix Groebert                        Jakub Wilk\n  Richard W. M. Jones                   Alexander Cherepanov\n  Tom Ritter                            Hovik Manucharyan\n  Sebastian Roschke                     Eberhard Mattes\n  Padraig Brady                         Ben Laurie\n  @dronesec                             Luca Barbato\n  Tobias Ospelt                         Thomas Jarosch\n  Martin Carpenter                      Mudge Zatko\n  Joe Zbiciak                           Ryan Govostes\n  Michael Rash                          William Robinet\n  Jonathan Gray                         Filipe Cabecinhas\n  Nico Weber                            Jodie Cunningham\n  Andrew Griffiths                      Parker Thompson\n  Jonathan Neuschfer                    Tyler Nighswander\n  Ben Nagy                              Samir Aguiar\n  Aidan Thornton                        Aleksandar Nikolich\n  Sam Hakim                             Laszlo Szekeres\n  David A. Wheeler                      Turo Lamminen\n  Andreas Stieger                       Richard Godbee\n  Louis Dassy                           teor2345\n  Alex Moneger                          Dmitry Vyukov\n  Keegan McAllister                     Kostya Serebryany\n  Richo Healey                          Martijn Bogaard\n  rc0r                                  Jonathan Foote\n  Christian Holler                      Dominique Pelle\n  Jacek Wielemborek                     Leo Barnes\n  Jeremy Barnes                         Jeff Trull\n  Guillaume Endignoux                   ilovezfs\n  Daniel Godas-Lopez                    Franjo Ivancic\n  Austin Seipp                          Daniel Komaromy\n  Daniel Binderman                      Jonathan Metzman\n  Vegard Nossum                         Jan Kneschke\n  Kurt Roeckx                           Marcel Bohme\n  Van-Thuan Pham                        Abhik Roychoudhury\n  Joshua J. Drake                       Toby Hutton\n  Rene Freingruber                      Sergey Davidoff\n  Sami Liedes                           Craig Young\n  Andrzej Jackowski                     Daniel Hodson\n```\n\nThank you!\n\n## 15) Contact\n\nQuestions? Concerns? Bug reports? Please use GitHub.\n\nThere is also a mailing list for the project; to join, send a mail to\n\u003cafl-users+subscribe@googlegroups.com\u003e. Or, if you prefer to browse\narchives first, try: [https://groups.google.com/group/afl-users](https://groups.google.com/group/afl-users).\n","funding_links":[],"categories":["Tools","Resources","Uncategorized","Secure Programming"],"sub_categories":["Network Protocol Fuzzers","By Purpose","Uncategorized","Fuzzing"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faflnet%2Faflnet","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faflnet%2Faflnet","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faflnet%2Faflnet/lists"}